Merge "Handle endpoint name nullability in constructor"
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index fcff581..45bb161 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -21,10 +21,6 @@
"soong_zip",
],
- tool_files: [
- ":libprotobuf-internal-protos",
- ],
-
cmd: "mkdir -p $(genDir)/$(in) " +
"&& $(location aprotoc) " +
" --plugin=$(location protoc-gen-javastream) " +
@@ -42,6 +38,11 @@
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
],
+
+ data: [
+ ":libprotobuf-internal-protos",
+ ],
+
output_extension: "srcjar",
}
@@ -53,10 +54,6 @@
"protoc-gen-cppstream",
],
- tool_files: [
- ":libprotobuf-internal-protos",
- ],
-
cmd: "mkdir -p $(genDir) " +
"&& $(location aprotoc) " +
" --plugin=$(location protoc-gen-cppstream) " +
@@ -73,6 +70,10 @@
"libs/incident/**/*.proto",
],
+ data: [
+ ":libprotobuf-internal-protos",
+ ],
+
output_extension: "proto.h",
}
diff --git a/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java b/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java
new file mode 100644
index 0000000..7927aa9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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 android.accessibility;
+
+import static junit.framework.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.perftests.utils.PerfTestActivity;
+import android.platform.test.annotations.LargeTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+public class AccessibilityPerfTest {
+
+ private static final String TEXT_KEY = "Child";
+
+ BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ ActivityTestRule<PerfTestActivity> mActivityTestRule =
+ new ActivityTestRule(PerfTestActivity.class);
+
+ @Rule
+ public RuleChain rules =
+ RuleChain.outerRule(mBenchmarkRule).around(mActivityTestRule);
+
+ private static Instrumentation sInstrumentation;
+
+ private Activity mActivity;
+
+ private ViewGroup createTestViewGroup(int children) {
+ ViewGroup group = new LinearLayout(mActivity.getBaseContext());
+ sInstrumentation.runOnMainSync(() -> {
+ mActivity.setContentView(group);
+ for (int i = 0; i < children; i++) {
+ TextView text = new TextView(mActivity.getBaseContext());
+ text.setText(TEXT_KEY);
+ group.addView(text);
+ }
+ });
+
+ return group;
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ }
+
+ @Before
+ public void setUp() {
+ mActivity = mActivityTestRule.getActivity();
+ }
+
+ @Test
+ public void testCreateAccessibilityNodeInfo() {
+ final BenchmarkState state = mBenchmarkRule.getState();
+ View view = new View(mActivity.getBaseContext());
+
+ while (state.keepRunning()) {
+ view.createAccessibilityNodeInfo();
+ }
+ }
+
+ @Test
+ public void testCreateViewGroupAccessibilityNodeInfo() {
+ final BenchmarkState state = mBenchmarkRule.getState();
+ ViewGroup group = createTestViewGroup(10);
+
+ while (state.keepRunning()) {
+ group.createAccessibilityNodeInfo();
+ }
+ }
+
+ @Test
+ public void testCreateAccessibilityEvent() {
+ final BenchmarkState state = mBenchmarkRule.getState();
+ View view = new View(mActivity.getBaseContext());
+
+ while (state.keepRunning()) {
+ view.onInitializeAccessibilityEvent(
+ new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED));
+ }
+ }
+
+ @Test
+ public void testPrefetching() throws Exception {
+ final BenchmarkState state = mBenchmarkRule.getState();
+ createTestViewGroup(AccessibilityNodeInfo.MAX_NUMBER_OF_PREFETCHED_NODES);
+ UiAutomation uiAutomation = sInstrumentation.getUiAutomation();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ uiAutomation.clearCache();
+ CountDownLatch latch = new CountDownLatch(
+ AccessibilityNodeInfo.MAX_NUMBER_OF_PREFETCHED_NODES);
+ uiAutomation.getCache().registerOnNodeAddedListener(
+ (node) -> {
+ latch.countDown();
+ });
+ state.resumeTiming();
+ // Get the root node, and await for the latch to have seen the expected max number
+ // of prefetched nodes.
+ uiAutomation.getRootInActiveWindow(
+ AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID
+ | AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE);
+ assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
+ }
+ }
+
+ @Test
+ public void testConnectUiAutomation() throws Exception {
+ final BenchmarkState state = mBenchmarkRule.getState();
+ while (state.keepRunning()) {
+ UiAutomation uiAutomation = sInstrumentation.getUiAutomation();
+ state.pauseTiming();
+ uiAutomation.destroy();
+ TestUtils.waitUntil(
+ "UiAutomation did not disconnect.", 10,
+ () -> uiAutomation.isDestroyed()
+ );
+ state.resumeTiming();
+ }
+ // We currently run into an exception
+ // if a test ends with UiAutomation explicitly disconnected,
+ // which seems to be the result of some commands being run by benchmarking.
+ sInstrumentation.getUiAutomation();
+ }
+}
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index fd8ddbc..6c8af39 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -59,6 +59,10 @@
*/
void reportAppUsage(String packageName, int userId);
+ /** @return {@code true} if the app is considered buggy from JobScheduler's perspective. */
+ boolean isAppConsideredBuggy(int callingUserId, @NonNull String callingPackageName,
+ int timeoutBlameUserId, @NonNull String timeoutBlamePackageName);
+
/**
* @return {@code true} if the given notification is associated with any user-initiated jobs.
*/
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 8583102..9299295 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -1911,6 +1911,7 @@
mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
mBroadcastOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
mMetricsHelper = new MetricsHelper(getContext(), mLock);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mListenerDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -2003,7 +2004,6 @@
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
}
- mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
publishLocalService(AlarmManagerInternal.class, new LocalService());
publishBinderService(Context.ALARM_SERVICE, mService);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
index 8a5d094..0717070 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
@@ -123,21 +123,21 @@
if (oldDetails == null) {
if (jobStatus.startedAsUserInitiatedJob) {
Counter.logIncrementWithUid(
- "job_scheduler.value_cntr_w_uid_initial_setNotification_call_required",
+ "job_scheduler.value_cntr_w_uid_initial_set_notification_call_required",
jobStatus.getUid());
} else {
Counter.logIncrementWithUid(
- "job_scheduler.value_cntr_w_uid_initial_setNotification_call_optional",
+ "job_scheduler.value_cntr_w_uid_initial_set_notification_call_optional",
jobStatus.getUid());
}
} else {
if (jobStatus.startedAsUserInitiatedJob) {
Counter.logIncrementWithUid(
- "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_required",
+ "job_scheduler.value_cntr_w_uid_subsequent_set_notification_call_required",
jobStatus.getUid());
} else {
Counter.logIncrementWithUid(
- "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_optional",
+ "job_scheduler.value_cntr_w_uid_subsequent_set_notification_call_optional",
jobStatus.getUid());
}
if (oldDetails.notificationId != notificationId) {
@@ -145,7 +145,7 @@
removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED,
jobStatus);
Counter.logIncrementWithUid(
- "job_scheduler.value_cntr_w_uid_setNotification_changed_notification_ids",
+ "job_scheduler.value_cntr_w_uid_set_notification_changed_notification_ids",
jobStatus.getUid());
}
}
@@ -200,7 +200,10 @@
// No more jobs using this notification. Apply the final job stop policy.
// If the user attempted to stop the job/app, then always remove the notification
// so the user doesn't get confused about the app state.
+ // Similarly, if the user background restricted the app, remove the notification so
+ // the user doesn't think the app is continuing to run in the background.
if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE
+ || stopReason == JobParameters.STOP_REASON_BACKGROUND_RESTRICTION
|| stopReason == JobParameters.STOP_REASON_USER) {
mNotificationManagerInternal.cancelNotification(
packageName, packageName, details.appUid, details.appPid, /* tag */ null,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index cbc9263..f99bcf1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -322,16 +322,25 @@
private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()";
private static final String QUOTA_TRACKER_SCHEDULE_LOGGED =
".schedulePersisted out-of-quota logged";
+ private static final String QUOTA_TRACKER_TIMEOUT_UIJ_TAG = "timeout-uij";
+ private static final String QUOTA_TRACKER_TIMEOUT_EJ_TAG = "timeout-ej";
+ private static final String QUOTA_TRACKER_TIMEOUT_REG_TAG = "timeout-reg";
+ private static final String QUOTA_TRACKER_TIMEOUT_TOTAL_TAG = "timeout-total";
+ private static final String QUOTA_TRACKER_ANR_TAG = "anr";
private static final Category QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED = new Category(
".schedulePersisted()");
private static final Category QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED = new Category(
".schedulePersisted out-of-quota logged");
- private static final Categorizer QUOTA_CATEGORIZER = (userId, packageName, tag) -> {
- if (QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG.equals(tag)) {
- return QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED;
- }
- return QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED;
- };
+ private static final Category QUOTA_TRACKER_CATEGORY_TIMEOUT_UIJ =
+ new Category(QUOTA_TRACKER_TIMEOUT_UIJ_TAG);
+ private static final Category QUOTA_TRACKER_CATEGORY_TIMEOUT_EJ =
+ new Category(QUOTA_TRACKER_TIMEOUT_EJ_TAG);
+ private static final Category QUOTA_TRACKER_CATEGORY_TIMEOUT_REG =
+ new Category(QUOTA_TRACKER_TIMEOUT_REG_TAG);
+ private static final Category QUOTA_TRACKER_CATEGORY_TIMEOUT_TOTAL =
+ new Category(QUOTA_TRACKER_TIMEOUT_TOTAL_TAG);
+ private static final Category QUOTA_TRACKER_CATEGORY_ANR = new Category(QUOTA_TRACKER_ANR_TAG);
+ private static final Category QUOTA_TRACKER_CATEGORY_DISABLED = new Category("disabled");
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
@@ -493,10 +502,18 @@
}
switch (name) {
case Constants.KEY_ENABLE_API_QUOTAS:
+ case Constants.KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC:
case Constants.KEY_API_QUOTA_SCHEDULE_COUNT:
case Constants.KEY_API_QUOTA_SCHEDULE_WINDOW_MS:
case Constants.KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT:
case Constants.KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT:
+ case Constants.KEY_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS:
if (!apiQuotaScheduleUpdated) {
mConstants.updateApiQuotaConstantsLocked();
updateQuotaTracker();
@@ -583,10 +600,26 @@
@VisibleForTesting
void updateQuotaTracker() {
- mQuotaTracker.setEnabled(mConstants.ENABLE_API_QUOTAS);
+ mQuotaTracker.setEnabled(
+ mConstants.ENABLE_API_QUOTAS || mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC);
mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED,
mConstants.API_QUOTA_SCHEDULE_COUNT,
mConstants.API_QUOTA_SCHEDULE_WINDOW_MS);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_TIMEOUT_UIJ,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_TIMEOUT_EJ,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_TIMEOUT_REG,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_TIMEOUT_TOTAL,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_ANR,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_ANR_COUNT,
+ mConstants.EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS);
}
/**
@@ -616,6 +649,8 @@
"conn_low_signal_strength_relax_frac";
private static final String KEY_PREFETCH_FORCE_BATCH_RELAX_THRESHOLD_MS =
"prefetch_force_batch_relax_threshold_ms";
+ // This has been enabled for 3+ full releases. We're unlikely to disable it.
+ // TODO(141645789): remove this flag
private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
private static final String KEY_API_QUOTA_SCHEDULE_COUNT = "aq_schedule_count";
private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms";
@@ -623,6 +658,22 @@
"aq_schedule_throw_exception";
private static final String KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
"aq_schedule_return_failure";
+ private static final String KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC =
+ "enable_execution_safeguards_udc";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT =
+ "es_u_timeout_uij_count";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT =
+ "es_u_timeout_ej_count";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT =
+ "es_u_timeout_reg_count";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT =
+ "es_u_timeout_total_count";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS =
+ "es_u_timeout_window_ms";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT =
+ "es_u_anr_count";
+ private static final String KEY_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS =
+ "es_u_anr_window_ms";
private static final String KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS =
"runtime_free_quota_max_limit_ms";
@@ -662,6 +713,17 @@
private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true;
private static final boolean DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
+ private static final boolean DEFAULT_ENABLE_EXECUTION_SAFEGUARDS_UDC = true;
+ private static final int DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
+ // EJs have a shorter timeout, so set a higher limit for them to start with.
+ private static final int DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = 5;
+ private static final int DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = 3;
+ private static final int DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT = 10;
+ private static final long DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS =
+ 24 * HOUR_IN_MILLIS;
+ private static final int DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT = 3;
+ private static final long DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS =
+ 6 * HOUR_IN_MILLIS;
@VisibleForTesting
public static final long DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = 30 * MINUTE_IN_MILLIS;
@VisibleForTesting
@@ -774,6 +836,55 @@
public boolean API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT =
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT;
+ /**
+ * Whether to enable the execution safeguards added in UDC.
+ */
+ public boolean ENABLE_EXECUTION_SAFEGUARDS_UDC = DEFAULT_ENABLE_EXECUTION_SAFEGUARDS_UDC;
+ /**
+ * The maximum number of times an app can have a user-iniated job time out before the system
+ * begins removing some of the app's privileges.
+ */
+ public int EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT;
+ /**
+ * The maximum number of times an app can have an expedited job time out before the system
+ * begins removing some of the app's privileges.
+ */
+ public int EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT;
+ /**
+ * The maximum number of times an app can have a regular job time out before the system
+ * begins removing some of the app's privileges.
+ */
+ public int EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT;
+ /**
+ * The maximum number of times an app can have jobs time out before the system
+ * attempts to restrict most of the app's privileges.
+ */
+ public int EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT;
+ /**
+ * The time window that {@link #EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT},
+ * {@link #EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT},
+ * {@link #EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT}, and
+ * {@link #EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT} should be evaluated over.
+ */
+ public long EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS;
+
+ /**
+ * The maximum number of times an app can ANR from JobScheduler's perspective before
+ * JobScheduler will attempt to restrict the app.
+ */
+ public int EXECUTION_SAFEGUARDS_UDC_ANR_COUNT = DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT;
+ /**
+ * The time window that {@link #EXECUTION_SAFEGUARDS_UDC_ANR_COUNT}
+ * should be evaluated over.
+ */
+ public long EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS =
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS;
+
/** The maximum amount of time we will let a job run for when quota is "free". */
public long RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
@@ -915,6 +1026,9 @@
private void updateApiQuotaConstantsLocked() {
ENABLE_API_QUOTAS = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_ENABLE_API_QUOTAS, DEFAULT_ENABLE_API_QUOTAS);
+ ENABLE_EXECUTION_SAFEGUARDS_UDC = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC, DEFAULT_ENABLE_EXECUTION_SAFEGUARDS_UDC);
// Set a minimum value on the quota limit so it's not so low that it interferes with
// legitimate use cases.
API_QUOTA_SCHEDULE_COUNT = Math.max(250,
@@ -931,6 +1045,40 @@
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT,
DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT);
+
+ // Set a minimum value on the timeout limit so it's not so low that it interferes with
+ // legitimate use cases.
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = Math.max(2,
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT));
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = Math.max(2,
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT));
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = Math.max(2,
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT));
+ final int highestTimeoutCount = Math.max(EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT,
+ Math.max(EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT));
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT = Math.max(highestTimeoutCount,
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT));
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS);
+ EXECUTION_SAFEGUARDS_UDC_ANR_COUNT = Math.max(1,
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT));
+ EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS,
+ DEFAULT_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS);
}
private void updateRuntimeConstantsLocked() {
@@ -1029,6 +1177,23 @@
pw.print(KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT,
API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT).println();
+ pw.print(KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC, ENABLE_EXECUTION_SAFEGUARDS_UDC)
+ .println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_TOTAL_COUNT).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS,
+ EXECUTION_SAFEGUARDS_UDC_TIMEOUT_WINDOW_MS).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_ANR_COUNT,
+ EXECUTION_SAFEGUARDS_UDC_ANR_COUNT).println();
+ pw.print(KEY_EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS,
+ EXECUTION_SAFEGUARDS_UDC_ANR_WINDOW_MS).println();
+
pw.print(KEY_RUNTIME_MIN_GUARANTEE_MS, RUNTIME_MIN_GUARANTEE_MS).println();
pw.print(KEY_RUNTIME_MIN_EJ_GUARANTEE_MS, RUNTIME_MIN_EJ_GUARANTEE_MS).println();
pw.print(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
@@ -2252,12 +2417,52 @@
// Set up the app standby bucketing tracker
mStandbyTracker = new StandbyTracker();
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- mQuotaTracker = new CountQuotaTracker(context, QUOTA_CATEGORIZER);
- mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED,
- mConstants.API_QUOTA_SCHEDULE_COUNT,
- mConstants.API_QUOTA_SCHEDULE_WINDOW_MS);
+
+ final Categorizer quotaCategorizer = (userId, packageName, tag) -> {
+ if (QUOTA_TRACKER_TIMEOUT_UIJ_TAG.equals(tag)) {
+ return mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC
+ ? QUOTA_TRACKER_CATEGORY_TIMEOUT_UIJ
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_TIMEOUT_EJ_TAG.equals(tag)) {
+ return mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC
+ ? QUOTA_TRACKER_CATEGORY_TIMEOUT_EJ
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_TIMEOUT_REG_TAG.equals(tag)) {
+ return mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC
+ ? QUOTA_TRACKER_CATEGORY_TIMEOUT_REG
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_TIMEOUT_TOTAL_TAG.equals(tag)) {
+ return mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC
+ ? QUOTA_TRACKER_CATEGORY_TIMEOUT_TOTAL
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_ANR_TAG.equals(tag)) {
+ return mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC
+ ? QUOTA_TRACKER_CATEGORY_ANR
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG.equals(tag)) {
+ return mConstants.ENABLE_API_QUOTAS
+ ? QUOTA_TRACKER_CATEGORY_SCHEDULE_PERSISTED
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ if (QUOTA_TRACKER_SCHEDULE_LOGGED.equals(tag)) {
+ return mConstants.ENABLE_API_QUOTAS
+ ? QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED
+ : QUOTA_TRACKER_CATEGORY_DISABLED;
+ }
+ Slog.wtf(TAG, "Unexpected category tag: " + tag);
+ return QUOTA_TRACKER_CATEGORY_DISABLED;
+ };
+ mQuotaTracker = new CountQuotaTracker(context, quotaCategorizer);
+ updateQuotaTracker();
// Log at most once per minute.
+ // Set outside updateQuotaTracker() since this is intentionally not configurable.
mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_SCHEDULE_LOGGED, 1, 60_000);
+ mQuotaTracker.setCountLimit(QUOTA_TRACKER_CATEGORY_DISABLED, Integer.MAX_VALUE, 60_000);
mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class);
mAppStandbyInternal.addListener(mStandbyTracker);
@@ -2762,6 +2967,48 @@
0 /* Reset cumulativeExecutionTime because of successful execution */);
}
+ @VisibleForTesting
+ void maybeProcessBuggyJob(@NonNull JobStatus jobStatus, int debugStopReason) {
+ boolean jobTimedOut = debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT;
+ // If madeActive = 0, the job never actually started.
+ if (!jobTimedOut && jobStatus.madeActive > 0) {
+ final long executionDurationMs = sUptimeMillisClock.millis() - jobStatus.madeActive;
+ // The debug reason may be different if we stopped the job for some other reason
+ // (eg. constraints), so look at total execution time to be safe.
+ if (jobStatus.startedAsUserInitiatedJob) {
+ // TODO: factor in different min guarantees for different UI job types
+ jobTimedOut = executionDurationMs >= mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ } else if (jobStatus.startedAsExpeditedJob) {
+ jobTimedOut = executionDurationMs >= mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS;
+ } else {
+ jobTimedOut = executionDurationMs >= mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ }
+ }
+ if (jobTimedOut) {
+ final int userId = jobStatus.getTimeoutBlameUserId();
+ final String pkg = jobStatus.getTimeoutBlamePackageName();
+ mQuotaTracker.noteEvent(userId, pkg,
+ jobStatus.startedAsUserInitiatedJob
+ ? QUOTA_TRACKER_TIMEOUT_UIJ_TAG
+ : (jobStatus.startedAsExpeditedJob
+ ? QUOTA_TRACKER_TIMEOUT_EJ_TAG
+ : QUOTA_TRACKER_TIMEOUT_REG_TAG));
+ if (!mQuotaTracker.noteEvent(userId, pkg, QUOTA_TRACKER_TIMEOUT_TOTAL_TAG)) {
+ mAppStandbyInternal.restrictApp(
+ pkg, userId, UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
+ }
+ }
+
+ if (debugStopReason == JobParameters.INTERNAL_STOP_REASON_ANR) {
+ final int callingUserId = jobStatus.getUserId();
+ final String callingPkg = jobStatus.getServiceComponent().getPackageName();
+ if (!mQuotaTracker.noteEvent(callingUserId, callingPkg, QUOTA_TRACKER_ANR_TAG)) {
+ mAppStandbyInternal.restrictApp(callingPkg, callingUserId,
+ UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
+ }
+ }
+ }
+
// JobCompletedListener implementations.
/**
@@ -2784,6 +3031,8 @@
mLastCompletedJobTimeElapsed[mLastCompletedJobIndex] = sElapsedRealtimeClock.millis();
mLastCompletedJobIndex = (mLastCompletedJobIndex + 1) % NUM_COMPLETED_JOB_HISTORY;
+ maybeProcessBuggyJob(jobStatus, debugStopReason);
+
if (debugStopReason == JobParameters.INTERNAL_STOP_REASON_UNINSTALL
|| debugStopReason == JobParameters.INTERNAL_STOP_REASON_DATA_CLEARED) {
// The job should have already been cleared from the rest of the JS tracking. No need
@@ -3511,26 +3760,36 @@
if (job.shouldTreatAsUserInitiatedJob()
&& checkRunUserInitiatedJobsPermission(
job.getSourceUid(), job.getSourcePackageName())) {
+ // The calling package is the one doing the work, so use it in the
+ // timeout quota checks.
+ final boolean isWithinTimeoutQuota = mQuotaTracker.isWithinQuota(
+ job.getTimeoutBlameUserId(), job.getTimeoutBlamePackageName(),
+ QUOTA_TRACKER_TIMEOUT_UIJ_TAG);
+ final long upperLimitMs = isWithinTimeoutQuota
+ ? mConstants.RUNTIME_UI_LIMIT_MS
+ : mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
if (job.getJob().getRequiredNetwork() != null) {
// User-initiated data transfers.
if (mConstants.RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS) {
final long estimatedTransferTimeMs =
mConnectivityController.getEstimatedTransferTimeMs(job);
if (estimatedTransferTimeMs == ConnectivityController.UNKNOWN_TIME) {
- return mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS;
+ return Math.min(upperLimitMs,
+ mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS);
}
// Try to give the job at least as much time as we think the transfer
// will take, but cap it at the maximum limit.
final long factoredTransferTimeMs = (long) (estimatedTransferTimeMs
* mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR);
- return Math.min(mConstants.RUNTIME_UI_LIMIT_MS,
+ return Math.min(upperLimitMs,
Math.max(factoredTransferTimeMs,
mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS));
}
- return Math.max(mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
- mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS);
+ return Math.min(upperLimitMs,
+ Math.max(mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mConstants.RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS));
}
- return mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ return Math.min(upperLimitMs, mConstants.RUNTIME_MIN_UI_GUARANTEE_MS);
} else if (job.shouldTreatAsExpeditedJob()) {
// Don't guarantee RESTRICTED jobs more than 5 minutes.
return job.getEffectiveStandbyBucket() != RESTRICTED_INDEX
@@ -3547,13 +3806,24 @@
synchronized (mLock) {
if (job.shouldTreatAsUserInitiatedJob()
&& checkRunUserInitiatedJobsPermission(
- job.getSourceUid(), job.getSourcePackageName())) {
+ job.getSourceUid(), job.getSourcePackageName())
+ && mQuotaTracker.isWithinQuota(job.getTimeoutBlameUserId(),
+ job.getTimeoutBlamePackageName(),
+ QUOTA_TRACKER_TIMEOUT_UIJ_TAG)) {
return mConstants.RUNTIME_UI_LIMIT_MS;
}
if (job.shouldTreatAsUserInitiatedJob()) {
return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
}
- return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ // Only let the app use the higher runtime if it hasn't repeatedly timed out.
+ final String timeoutTag = job.shouldTreatAsExpeditedJob()
+ ? QUOTA_TRACKER_TIMEOUT_EJ_TAG : QUOTA_TRACKER_TIMEOUT_REG_TAG;
+ final long upperLimitMs =
+ mQuotaTracker.isWithinQuota(job.getTimeoutBlameUserId(),
+ job.getTimeoutBlamePackageName(), timeoutTag)
+ ? mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS
+ : mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ return Math.min(upperLimitMs,
mConstants.USE_TARE_POLICY
? mTareController.getMaxJobExecutionTimeMsLocked(job)
: mQuotaController.getMaxJobExecutionTimeMsLocked(job));
@@ -3797,6 +4067,17 @@
}
@Override
+ public boolean isAppConsideredBuggy(int callingUserId, @NonNull String callingPackageName,
+ int timeoutBlameUserId, @NonNull String timeoutBlamePackageName) {
+ return !mQuotaTracker.isWithinQuota(callingUserId, callingPackageName,
+ QUOTA_TRACKER_ANR_TAG)
+ || !mQuotaTracker.isWithinQuota(callingUserId, callingPackageName,
+ QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG)
+ || !mQuotaTracker.isWithinQuota(timeoutBlameUserId, timeoutBlamePackageName,
+ QUOTA_TRACKER_TIMEOUT_TOTAL_TAG);
+ }
+
+ @Override
public boolean isNotificationAssociatedWithAnyUserInitiatedJobs(int notificationId,
int userId, @NonNull String packageName) {
if (packageName == null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 0b08b6f..109686d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -413,16 +413,22 @@
final Intent intent = new Intent().setComponent(job.getServiceComponent())
.setFlags(Intent.FLAG_FROM_BACKGROUND);
boolean binding = false;
+ boolean startedWithForegroundFlag = false;
try {
final Context.BindServiceFlags bindFlags;
- if (job.shouldTreatAsUserInitiatedJob()) {
+ if (job.shouldTreatAsUserInitiatedJob() && !job.isUserBgRestricted()) {
+ // If the user has bg restricted the app, don't give the job FG privileges
+ // such as bypassing data saver or getting the higher foreground proc state.
+ // If we've gotten to this point, the app is most likely in the foreground,
+ // so the job will run just fine while the user keeps the app in the foreground.
bindFlags = Context.BindServiceFlags.of(
Context.BIND_AUTO_CREATE
| Context.BIND_ALMOST_PERCEPTIBLE
| Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS
| Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS
| Context.BIND_NOT_APP_COMPONENT_USAGE);
- } else if (job.shouldTreatAsExpeditedJob()) {
+ startedWithForegroundFlag = true;
+ } else if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) {
bindFlags = Context.BindServiceFlags.of(
Context.BIND_AUTO_CREATE
| Context.BIND_NOT_FOREGROUND
@@ -535,8 +541,11 @@
mAvailable = false;
mStoppedReason = null;
mStoppedTime = 0;
+ // Wait until after bindService() returns a success value to set these so we don't
+ // have JobStatus objects that aren't running but have these set to true.
job.startedAsExpeditedJob = job.shouldTreatAsExpeditedJob();
job.startedAsUserInitiatedJob = job.shouldTreatAsUserInitiatedJob();
+ job.startedWithForegroundFlag = startedWithForegroundFlag;
return true;
}
}
@@ -1331,7 +1340,7 @@
// FINISHED/NO-RETRY.
onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true,
/* texCounterMetricId */
- "job_scheduler.value_cntr_w_uid_slow_app_response_onStartJob",
+ "job_scheduler.value_cntr_w_uid_slow_app_response_on_start_job",
/* debugReason */ "timed out while starting",
/* anrMessage */ "No response to onStartJob",
CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
@@ -1343,7 +1352,7 @@
// other reason.
onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ false,
/* texCounterMetricId */
- "job_scheduler.value_cntr_w_uid_slow_app_response_onStopJob",
+ "job_scheduler.value_cntr_w_uid_slow_app_response_on_stop_job",
/* debugReason */ "timed out while stopping",
/* anrMessage */ "No response to onStopJob",
CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
@@ -1400,7 +1409,7 @@
} else if (mAwaitingNotification) {
onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true,
/* texCounterMetricId */
- "job_scheduler.value_cntr_w_uid_slow_app_response_setNotification",
+ "job_scheduler.value_cntr_w_uid_slow_app_response_set_notification",
/* debugReason */ "timed out while stopping",
/* anrMessage */ "required notification not provided",
/* triggerAnr */ true);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 0a7bffc..098b2fb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -1184,6 +1184,12 @@
}
}
+ /** Returns the {@link String#intern() interned} String if it's not null. */
+ @Nullable
+ private static String intern(@Nullable String val) {
+ return val == null ? null : val.intern();
+ }
+
private List<JobStatus> readJobMapImpl(InputStream fis, boolean rtcIsGood, long nowElapsed)
throws XmlPullParserException, IOException {
TypedXmlPullParser parser = Xml.resolvePullParser(fis);
@@ -1298,8 +1304,8 @@
}
String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
- final String namespace = parser.getAttributeValue(null, "namespace");
- final String sourceTag = parser.getAttributeValue(null, "sourceTag");
+ final String namespace = intern(parser.getAttributeValue(null, "namespace"));
+ final String sourceTag = intern(parser.getAttributeValue(null, "sourceTag"));
int eventType;
// Read out constraints tag.
@@ -1461,7 +1467,7 @@
final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName,
sourceUserId, nowElapsed);
JobStatus js = new JobStatus(
- builtJob, uid, sourcePackageName, sourceUserId,
+ builtJob, uid, intern(sourcePackageName), sourceUserId,
appBucket, namespace, sourceTag,
elapsedRuntimes.first, elapsedRuntimes.second,
lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTime,
@@ -1478,8 +1484,8 @@
throws XmlPullParserException {
// Pull out required fields from <job> attributes.
int jobId = parser.getAttributeInt(null, "jobid");
- String packageName = parser.getAttributeValue(null, "package");
- String className = parser.getAttributeValue(null, "class");
+ String packageName = intern(parser.getAttributeValue(null, "package"));
+ String className = intern(parser.getAttributeValue(null, "class"));
ComponentName cname = new ComponentName(packageName, className);
return new JobInfo.Builder(jobId, cname);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index ecee10a..25b3421 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -19,6 +19,7 @@
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -205,8 +206,32 @@
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
- final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
- jobStatus.canRunInBatterySaver());
+ final boolean isUserBgRestricted =
+ !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+ && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName);
+ // If a job started with the foreground flag, it'll cause the UID to stay active
+ // and thus cause areJobsRestricted() to always return false, so if
+ // areJobsRestricted() returns false and the app is BG restricted and not TOP,
+ // we need to stop any jobs that started with the foreground flag so they don't
+ // keep the app in an elevated proc state. If we were to get in this situation,
+ // then the user restricted the app after the job started, so it's best to stop
+ // the job as soon as possible, especially since the job would be visible to the
+ // user (with a notification and in Task Manager).
+ // There are several other reasons that uidActive can be true for an app even if its
+ // proc state is less important than BFGS.
+ // JobScheduler has historically (at least up through UDC) allowed the app's jobs to run
+ // when its UID was active, even if it's background restricted. This has been fine because
+ // JobScheduler stops the job as soon as the UID becomes inactive and the jobs themselves
+ // will not keep the UID active. The logic here is to ensure that special jobs
+ // (e.g. user-initiated jobs) themselves do not keep the UID active when the app is
+ // background restricted.
+ final boolean shouldStopImmediately = jobStatus.startedWithForegroundFlag
+ && isUserBgRestricted
+ && mService.getUidProcState(uid)
+ > ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ final boolean canRun = !shouldStopImmediately
+ && !mAppStateTracker.areJobsRestricted(
+ uid, packageName, jobStatus.canRunInBatterySaver());
final boolean isActive;
if (activeState == UNKNOWN) {
@@ -219,8 +244,7 @@
}
boolean didChange =
jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun,
- !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
- && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
+ isUserBgRestricted);
didChange |= jobStatus.setUidActive(isActive);
return didChange;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f6bdb93..6d938de 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -1774,6 +1774,12 @@
}
pw.println();
+ if (mBackgroundMeteredAllowed.size() > 0) {
+ pw.print("Background metered allowed: ");
+ pw.println(mBackgroundMeteredAllowed);
+ pw.println();
+ }
+
pw.println("Current default network callbacks:");
pw.increaseIndent();
for (int i = 0; i < mCurrentDefaultNetworkCallbacks.size(); i++) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index edd531d..13903ac 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -430,6 +430,13 @@
* when it started running. This isn't copied over when a job is rescheduled.
*/
public boolean startedAsUserInitiatedJob = false;
+ /**
+ * Whether this particular JobStatus instance started with the foreground flag
+ * (or more accurately, did <b>not</b> have the
+ * {@link android.content.Context#BIND_NOT_FOREGROUND} flag
+ * included in its binding flags when started).
+ */
+ public boolean startedWithForegroundFlag = false;
public boolean startedWithImmediacyPrivilege = false;
@@ -1088,13 +1095,77 @@
return UserHandle.getUserId(callingUid);
}
+ private boolean shouldBlameSourceForTimeout() {
+ // If the system scheduled the job on behalf of an app, assume the app is the one
+ // doing the work and blame the app directly. This is the case with things like
+ // syncs via SyncManager.
+ // If the system didn't schedule the job on behalf of an app, then
+ // blame the app doing the actual work. Proxied jobs are a little tricky.
+ // Proxied jobs scheduled by built-in system apps like DownloadManager may be fine
+ // and we could consider exempting those jobs. For example, in DownloadManager's
+ // case, all it does is download files and the code is vetted. A timeout likely
+ // means it's downloading a large file, which isn't an error. For now, DownloadManager
+ // is an exempted app, so this shouldn't be an issue.
+ // However, proxied jobs coming from other system apps (such as those that can
+ // be updated separately from an OTA) may not be fine and we would want to apply
+ // this policy to those jobs/apps.
+ // TODO(284512488): consider exempting DownloadManager or other system apps
+ return UserHandle.isCore(callingUid);
+ }
+
+ /**
+ * Returns the package name that should most likely be blamed for the job timing out.
+ */
+ public String getTimeoutBlamePackageName() {
+ if (shouldBlameSourceForTimeout()) {
+ return sourcePackageName;
+ }
+ return getServiceComponent().getPackageName();
+ }
+
+ /**
+ * Returns the UID that should most likely be blamed for the job timing out.
+ */
+ public int getTimeoutBlameUid() {
+ if (shouldBlameSourceForTimeout()) {
+ return sourceUid;
+ }
+ return callingUid;
+ }
+
+ /**
+ * Returns the userId that should most likely be blamed for the job timing out.
+ */
+ public int getTimeoutBlameUserId() {
+ if (shouldBlameSourceForTimeout()) {
+ return sourceUserId;
+ }
+ return UserHandle.getUserId(callingUid);
+ }
+
/**
* Returns an appropriate standby bucket for the job, taking into account any standby
* exemptions.
*/
public int getEffectiveStandbyBucket() {
+ final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
+ final boolean isBuggy = jsi.isAppConsideredBuggy(
+ getUserId(), getServiceComponent().getPackageName(),
+ getTimeoutBlameUserId(), getTimeoutBlamePackageName());
+
final int actualBucket = getStandbyBucket();
if (actualBucket == EXEMPTED_INDEX) {
+ // EXEMPTED apps always have their jobs exempted, even if they're buggy, because the
+ // user has explicitly told the system to avoid restricting the app for power reasons.
+ if (isBuggy) {
+ final String pkg;
+ if (getServiceComponent().getPackageName().equals(sourcePackageName)) {
+ pkg = sourcePackageName;
+ } else {
+ pkg = getServiceComponent().getPackageName() + "/" + sourcePackageName;
+ }
+ Slog.w(TAG, "Exempted app " + pkg + " considered buggy");
+ }
return actualBucket;
}
if (uidActive || getJob().isExemptedFromAppStandby()) {
@@ -1102,13 +1173,18 @@
// like other ACTIVE apps.
return ACTIVE_INDEX;
}
+ // If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket
+ // (potentially because it's used frequently by the user), limit its effective bucket
+ // so that it doesn't get to run as much as a normal ACTIVE app.
+ final int highestBucket = isBuggy ? WORKING_INDEX : ACTIVE_INDEX;
if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX
&& mHasMediaBackupExemption) {
- // Cap it at WORKING_INDEX as media back up jobs are important to the user, and the
+ // Treat it as if it's at least WORKING_INDEX since media backup jobs are important
+ // to the user, and the
// source package may not have been used directly in a while.
- return Math.min(WORKING_INDEX, actualBucket);
+ return Math.max(highestBucket, Math.min(WORKING_INDEX, actualBucket));
}
- return actualBucket;
+ return Math.max(highestBucket, actualBucket);
}
/** Returns the real standby bucket of the job. */
@@ -1537,6 +1613,10 @@
* for any reason.
*/
public boolean shouldTreatAsUserInitiatedJob() {
+ // isUserBgRestricted is intentionally excluded from this method. It should be fine to
+ // treat the job as a UI job while the app is TOP, but just not in the background.
+ // Instead of adding a proc state check here, the parts of JS that can make the distinction
+ // and care about the distinction can do the check.
return getJob().isUserInitiated()
&& (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) == 0
&& (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ) == 0;
@@ -1584,6 +1664,11 @@
&& (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
}
+ /** Returns whether or not the app is background restricted by the user (FAS). */
+ public boolean isUserBgRestricted() {
+ return mIsUserBgRestricted;
+ }
+
/** @return true if the constraint was changed, false otherwise. */
boolean setChargingConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_CHARGING, nowElapsed, state);
@@ -2733,6 +2818,12 @@
}
pw.decreaseIndent();
+ pw.print("Started with foreground flag: ");
+ pw.println(startedWithForegroundFlag);
+ if (mIsUserBgRestricted) {
+ pw.println("User BG restricted");
+ }
+
if (changedAuthorities != null) {
pw.println("Changed authorities:");
pw.increaseIndent();
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 07958dd..1c29982 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
@@ -773,6 +773,14 @@
// If quota is currently "free", then the job can run for the full amount of time,
// regardless of bucket (hence using charging instead of isQuotaFreeLocked()).
if (mService.isBatteryCharging()
+ // The top and foreground cases here were added because apps in those states
+ // aren't really restricted and the work could be something the user is
+ // waiting for. Now that user-initiated jobs are a defined concept, we may
+ // not need these exemptions as much. However, UIJs are currently limited
+ // (as of UDC) to data transfer work. There may be other work that could
+ // rely on this exception. Once we add more UIJ types, we can re-evaluate
+ // the need for these exceptions.
+ // TODO: re-evaluate the need for these exceptions
|| mTopAppCache.get(jobStatus.getSourceUid())
|| isTopStartedJobLocked(jobStatus)
|| isUidInForeground(jobStatus.getSourceUid())) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 08439f3..87e1249 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -433,6 +433,12 @@
}
}
+ /** Returns the {@link String#intern() interned} String if it's not null. */
+ @Nullable
+ private static String intern(@Nullable String val) {
+ return val == null ? null : val.intern();
+ }
+
/**
* @param parser Xml parser at the beginning of a "<ledger/>" tag. The next "parser.next()" call
* will take the parser into the body of the ledger tag.
@@ -448,7 +454,7 @@
final List<Ledger.Transaction> transactions = new ArrayList<>();
final List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
- pkgName = parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME);
+ pkgName = intern(parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME));
curBalance = parser.getAttributeLong(null, XML_ATTR_CURRENT_BALANCE);
final boolean isInstalled = validPackages.contains(pkgName);
@@ -487,7 +493,7 @@
}
continue;
}
- final String tag = parser.getAttributeValue(null, XML_ATTR_TAG);
+ final String tag = intern(parser.getAttributeValue(null, XML_ATTR_TAG));
final long startTime = parser.getAttributeLong(null, XML_ATTR_START_TIME);
final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 55e6815..7d38377 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -3025,7 +3025,7 @@
public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT =
COMPRESS_TIME ? ONE_MINUTE : 30 * ONE_MINUTE;
public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS =
- COMPRESS_TIME ? ONE_MINUTE : ONE_DAY;
+ COMPRESS_TIME ? ONE_MINUTE : ONE_HOUR;
public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
public static final long DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
2 * ONE_MINUTE;
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 93d20dd..ed5a8f2 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -341,7 +341,7 @@
}
java_library {
- name: "android_stubs_current",
+ name: "android_stubs_current.from-source",
static_libs: [
"all-modules-public-stubs",
"android-non-updatable.stubs",
@@ -351,7 +351,7 @@
}
java_library {
- name: "android_system_stubs_current",
+ name: "android_system_stubs_current.from-source",
static_libs: [
"all-modules-system-stubs",
"android-non-updatable.stubs.system",
@@ -375,7 +375,7 @@
}
java_library {
- name: "android_test_stubs_current",
+ name: "android_test_stubs_current.from-source",
static_libs: [
// Updatable modules do not have test APIs, but we want to include their SystemApis, like we
// include the SystemApi of framework-non-updatable-sources.
@@ -395,7 +395,7 @@
}
java_library {
- name: "android_module_lib_stubs_current",
+ name: "android_module_lib_stubs_current.from-source",
defaults: [
"android.jar_defaults",
"android_stubs_dists_default",
@@ -411,7 +411,7 @@
}
java_library {
- name: "android_system_server_stubs_current",
+ name: "android_system_server_stubs_current.from-source",
defaults: [
"android.jar_defaults",
"android_stubs_dists_default",
@@ -419,7 +419,7 @@
srcs: [":services-non-updatable-stubs"],
installable: false,
static_libs: [
- "android_module_lib_stubs_current",
+ "android_module_lib_stubs_current.from-source",
],
dist: {
dir: "apistubs/android/system-server",
diff --git a/api/api.go b/api/api.go
index af817b5..c568a45 100644
--- a/api/api.go
+++ b/api/api.go
@@ -96,6 +96,7 @@
Sdk_version *string
Static_libs []string
Visibility []string
+ Defaults []string
}
type fgProps struct {
@@ -362,6 +363,30 @@
}
}
+func createFullApiLibraries(ctx android.LoadHookContext) {
+ javaLibraryNames := []string{
+ "android_stubs_current",
+ "android_system_stubs_current",
+ "android_test_stubs_current",
+ "android_module_lib_stubs_current",
+ "android_system_server_stubs_current",
+ }
+
+ for _, libraryName := range javaLibraryNames {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr(libraryName)
+ staticLib := libraryName + ".from-source"
+ if ctx.Config().BuildFromTextStub() {
+ staticLib = libraryName + ".from-text"
+ }
+ props.Static_libs = []string{staticLib}
+ props.Defaults = []string{"android.jar_defaults"}
+ props.Visibility = []string{"//visibility:public"}
+
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+}
+
func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
bootclasspath := a.properties.Bootclasspath
system_server_classpath := a.properties.System_server_classpath
@@ -382,6 +407,8 @@
createPublicStubsSourceFilegroup(ctx, bootclasspath)
createApiContributionDefaults(ctx, bootclasspath)
+
+ createFullApiLibraries(ctx)
}
func combinedApisModuleFactory() android.Module {
diff --git a/api/api_test.go b/api/api_test.go
index 15b695c..1f4c2af 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -19,6 +19,7 @@
"android/soong/android"
"android/soong/bp2build"
+ "android/soong/java"
)
func runCombinedApisTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2build.Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
@@ -30,7 +31,9 @@
func runCombinedApisTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
t.Helper()
- runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
+ runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_defaults", java.DefaultsFactory)
+ })
}
func TestCombinedApisGeneral(t *testing.T) {
@@ -42,6 +45,13 @@
system_server_classpath: ["ssc"],
}
`,
+ Filesystem: map[string]string{
+ "a/Android.bp": `
+ java_defaults {
+ name: "android.jar_defaults",
+ }
+ `,
+ },
ExpectedBazelTargets: []string{
bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-current.txt", bp2build.AttrNameToString{
"scope": `"public"`,
diff --git a/core/api/current.txt b/core/api/current.txt
index 1d3e275..a2c1b1b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -54921,6 +54921,7 @@
public class AnimationUtils {
ctor public AnimationUtils();
method public static long currentAnimationTimeMillis();
+ method public static long getExpectedPresentationTimeNanos();
method public static android.view.animation.Animation loadAnimation(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
method public static android.view.animation.Interpolator loadInterpolator(android.content.Context, @AnimRes @InterpolatorRes int) throws android.content.res.Resources.NotFoundException;
method public static android.view.animation.LayoutAnimationController loadLayoutAnimation(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9dca29a..529604d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2979,6 +2979,10 @@
method @Deprecated public boolean isBound();
}
+ public class NotificationRankingUpdate implements android.os.Parcelable {
+ method public final boolean isFdNotNullAndClosed();
+ }
+
}
package android.service.quickaccesswallet {
@@ -3415,7 +3419,9 @@
}
public final class Choreographer {
+ method public long getExpectedPresentationTimeNanos();
method public static long getFrameDelay();
+ method public long getFrameTimeNanos();
method public void postCallback(int, Runnable, Object);
method public void postCallbackDelayed(int, Runnable, Object, long);
method public void removeCallbacks(int, Runnable, Object);
@@ -3628,7 +3634,7 @@
package android.view.animation {
public class AnimationUtils {
- method public static void lockAnimationClock(long);
+ method public static void lockAnimationClock(long, long);
method public static void unlockAnimationClock();
}
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 2198fcd..f67c68e 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -111,20 +111,20 @@
float pathErrorScale) throws NotFoundException {
final ConfigurationBoundResourceCache<Animator> animatorCache = resources
.getAnimatorCache();
- ConfigurationBoundResourceCache.Entry<Animator> animatorEntry =
- animatorCache.getInstance(id, resources, theme);
- if (animatorEntry.hasValue()) {
+ Animator animator = animatorCache.getInstance(id, resources, theme);
+ if (animator != null) {
if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
}
- return animatorEntry.getValue();
+ return animator;
} else if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
}
+ int cacheGeneration = animatorCache.getGeneration();
XmlResourceParser parser = null;
try {
parser = resources.getAnimation(id);
- Animator animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+ animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
if (animator != null) {
animator.appendChangingConfigurations(getChangingConfigs(resources, id));
final ConstantState<Animator> constantState = animator.createConstantState();
@@ -132,7 +132,7 @@
if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
}
- animatorCache.put(id, theme, constantState, animatorEntry.getGeneration());
+ animatorCache.put(id, theme, constantState, cacheGeneration);
// create a new animator so that cached version is never used by the user
animator = constantState.newInstance(resources, theme);
}
@@ -161,22 +161,22 @@
final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
.getStateListAnimatorCache();
final Theme theme = context.getTheme();
- ConfigurationBoundResourceCache.Entry<StateListAnimator> animatorEntry =
- cache.getInstance(id, resources, theme);
- if (animatorEntry.hasValue()) {
- return animatorEntry.getValue();
+ StateListAnimator animator = cache.getInstance(id, resources, theme);
+ if (animator != null) {
+ return animator;
}
+ int cacheGeneration = cache.getGeneration();
XmlResourceParser parser = null;
try {
parser = resources.getAnimation(id);
- StateListAnimator animator =
+ animator =
createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
if (animator != null) {
animator.appendChangingConfigurations(getChangingConfigs(resources, id));
final ConstantState<StateListAnimator> constantState = animator
.createConstantState();
if (constantState != null) {
- cache.put(id, theme, constantState, animatorEntry.getGeneration());
+ cache.put(id, theme, constantState, cacheGeneration);
// return a clone so that the animator in constant state is never used.
animator = constantState.newInstance(resources, theme);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 259e516..bcd43ea 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1477,9 +1477,26 @@
public static final int OP_RECORD_AUDIO_SANDBOXED =
AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED;
+ /**
+ * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered.
+ *
+ * @hide
+ */
+ public static final int OP_RECEIVE_SANDBOX_TRIGGER_AUDIO =
+ AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
+
+ /**
+ * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve the
+ * hotword training model.
+ *
+ * @hide
+ */
+ public static final int OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
+ AppProtoEnums.APP_OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 136;
+ public static final int _NUM_OP = 138;
/**
* All app ops represented as strings.
@@ -1621,7 +1638,9 @@
OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
OPSTR_USE_FULL_SCREEN_INTENT,
OPSTR_CAMERA_SANDBOXED,
- OPSTR_RECORD_AUDIO_SANDBOXED
+ OPSTR_RECORD_AUDIO_SANDBOXED,
+ OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+ OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO
})
public @interface AppOpString {}
@@ -2232,6 +2251,23 @@
*/
public static final String OPSTR_USE_FULL_SCREEN_INTENT = "android:use_full_screen_intent";
+ /**
+ * Allows the assistant app to receive the PCC-validated hotword and be voice-triggered.
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO =
+ "android:receive_sandbox_trigger_audio";
+
+ /**
+ * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve
+ * the hotword training model.
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
+ "android:receive_sandbox_negative_data_audio";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2769,7 +2805,13 @@
new AppOpInfo.Builder(OP_CAMERA_SANDBOXED, OPSTR_CAMERA_SANDBOXED,
"CAMERA_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_RECORD_AUDIO_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED,
- "RECORD_AUDIO_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
+ "RECORD_AUDIO_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+ OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+ "RECEIVE_SANDBOX_TRIGGER_AUDIO").build(),
+ new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
+ OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
+ "RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO").build()
};
// The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 82f4315..2056eca 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3478,6 +3478,16 @@
((CompatResources) r).setContext(this);
}
mResources = r;
+
+ // only do this if the user already has more than one preferred locale
+ if (r.getConfiguration().getLocales().size() > 1) {
+ LocaleConfig lc = LocaleConfig.fromContextIgnoringOverride(this);
+ mResourcesManager.setLocaleList(lc != null
+ && lc.getSupportedLocales() != null
+ && !lc.getSupportedLocales().isEmpty()
+ ? lc.getSupportedLocales()
+ : null);
+ }
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0ec3847..46260ea 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -607,6 +607,7 @@
void killPackageDependents(in String packageName, int userId);
void makePackageIdle(String packageName, int userId);
+ void setDeterministicUidIdle(boolean deterministic);
int getMemoryTrimLevel();
boolean isVrModePackageEnabled(in ComponentName packageName);
void notifyLockedProfile(int userId);
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 09450f5..e7a2b61e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -117,6 +117,26 @@
"android.app.action.CONFIRM_REMOTE_DEVICE_CREDENTIAL";
/**
+ * Intent used to prompt user for device credential for entering repair
+ * mode. If the credential is verified successfully, then the information
+ * needed to verify the credential again will be written to a location that
+ * is available to repair mode. This makes it possible for repair mode to
+ * require that the same credential be provided to exit repair mode.
+ * @hide
+ */
+ public static final String ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL =
+ "android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL";
+
+ /**
+ * Intent used to prompt user for device credential that is written by
+ * {@link #ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL} for exiting
+ * repair mode.
+ * @hide
+ */
+ public static final String ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL =
+ "android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL";
+
+ /**
* A CharSequence dialog title to show to the user when used with a
* {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
* @hide
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 5031a33..729e555 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -138,6 +138,10 @@
try {
//Get the resource id
resId = new ApplicationInfo(context.getApplicationInfo()).getLocaleConfigRes();
+ if (resId == 0) {
+ mStatus = STATUS_NOT_SPECIFIED;
+ return;
+ }
//Get the parser to read XML data
XmlResourceParser parser = res.getXml(resId);
parseLocaleConfig(parser, res);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 7e6386e..1ecb5d3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -36,6 +36,7 @@
import android.content.res.loader.ResourcesLoader;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.Process;
import android.os.Trace;
import android.util.ArrayMap;
@@ -118,6 +119,11 @@
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
private final ReferenceQueue<Resources> mResourcesReferencesQueue = new ReferenceQueue<>();
+ /**
+ * The list of locales the app declares it supports.
+ */
+ private LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
+
private static class ApkKey {
public final String path;
public final boolean sharedLib;
@@ -1605,6 +1611,22 @@
}
}
+ /**
+ * Returns the LocaleList current set
+ */
+ public LocaleList getLocaleList() {
+ return mLocaleList;
+ }
+
+ /**
+ * Sets the LocaleList of app's supported locales
+ */
+ public void setLocaleList(LocaleList localeList) {
+ if ((localeList != null) && !localeList.isEmpty()) {
+ mLocaleList = localeList;
+ }
+ }
+
private class UpdateHandler implements Resources.UpdateCallbacks {
/**
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 4b8cfd5..c4e4995 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -334,6 +334,12 @@
public boolean isVisible;
/**
+ * Whether this task is request visible.
+ * @hide
+ */
+ public boolean isVisibleRequested;
+
+ /**
* Whether this task is sleeping due to sleeping display.
* @hide
*/
@@ -518,6 +524,7 @@
&& Objects.equals(taskDescription, that.taskDescription)
&& isFocused == that.isFocused
&& isVisible == that.isVisible
+ && isVisibleRequested == that.isVisibleRequested
&& isSleeping == that.isSleeping
&& Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
&& parentTaskId == that.parentTaskId
@@ -591,6 +598,7 @@
parentTaskId = source.readInt();
isFocused = source.readBoolean();
isVisible = source.readBoolean();
+ isVisibleRequested = source.readBoolean();
isSleeping = source.readBoolean();
topActivityInSizeCompat = source.readBoolean();
topActivityEligibleForLetterboxEducation = source.readBoolean();
@@ -644,6 +652,7 @@
dest.writeInt(parentTaskId);
dest.writeBoolean(isFocused);
dest.writeBoolean(isVisible);
+ dest.writeBoolean(isVisibleRequested);
dest.writeBoolean(isSleeping);
dest.writeBoolean(topActivityInSizeCompat);
dest.writeBoolean(topActivityEligibleForLetterboxEducation);
@@ -687,6 +696,7 @@
+ " parentTaskId=" + parentTaskId
+ " isFocused=" + isFocused
+ " isVisible=" + isVisible
+ + " isVisibleRequested=" + isVisibleRequested
+ " isSleeping=" + isSleeping
+ " topActivityInSizeCompat=" + topActivityInSizeCompat
+ " topActivityEligibleForLetterboxEducation= "
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 247d5bc..b613fae 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -553,6 +553,21 @@
}
/**
+ * Provides reference to the cache through a locked connection.
+ *
+ * @return the accessibility cache.
+ * @hide
+ */
+ public @Nullable AccessibilityCache getCache() {
+ final int connectionId;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ connectionId = mConnectionId;
+ }
+ return AccessibilityInteractionClient.getCache(connectionId);
+ }
+
+ /**
* Adopt the permission identity of the shell UID for all permissions. This allows
* you to call APIs protected permissions which normal apps cannot hold but are
* granted to the shell UID. If you already adopted all shell permissions by calling
@@ -827,6 +842,22 @@
* established.
*/
public AccessibilityNodeInfo getRootInActiveWindow() {
+ return getRootInActiveWindow(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ }
+
+ /**
+ * Gets the root {@link AccessibilityNodeInfo} in the active window.
+ *
+ * @param prefetchingStrategy the prefetching strategy.
+ * @return The root info.
+ * @throws IllegalStateException If the connection to the accessibility subsystem is not
+ * established.
+ *
+ * @hide
+ */
+ @Nullable
+ public AccessibilityNodeInfo getRootInActiveWindow(
+ @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) {
final int connectionId;
synchronized (mLock) {
throwIfNotConnectedLocked();
@@ -834,8 +865,7 @@
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
- .getRootInActiveWindow(connectionId,
- AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
+ .getRootInActiveWindow(connectionId, prefetchingStrategy);
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 9d6430b..993b73d 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -913,7 +913,7 @@
* instead the default system wallpaper is returned
* (some versions of T may throw a {@code SecurityException}).</li>
* <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
+ * and will always throw a {@code SecurityException}.</li>
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
@@ -935,18 +935,9 @@
}
/**
- * <strong> Important note: </strong>
- * <ul>
- * <li>Up to version S, this method requires the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
- * <li>Starting in T, directly accessing the wallpaper is not possible anymore,
- * instead the default system wallpaper is returned
- * (some versions of T may throw a {@code SecurityException}).</li>
- * <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
- * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
- * can still access the real wallpaper on all versions. </li>
- * </ul>
+ * <strong> Important note: </strong> only apps with
+ * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} should use this method.
+ * Otherwise, a {@code SecurityException} will be thrown.
*
* <p>
* Retrieve the requested wallpaper for the specified wallpaper type if the wallpaper is not
@@ -1206,7 +1197,7 @@
* instead the default system wallpaper is returned
* (some versions of T may throw a {@code SecurityException}).</li>
* <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
+ * and will always throw a {@code SecurityException}.</li>
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
@@ -1228,18 +1219,9 @@
}
/**
- * <strong> Important note: </strong>
- * <ul>
- * <li>Up to version S, this method requires the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
- * <li>Starting in T, directly accessing the wallpaper is not possible anymore,
- * instead the default system wallpaper is returned
- * (some versions of T may throw a {@code SecurityException}).</li>
- * <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
- * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
- * can still access the real wallpaper on all versions. </li>
- * </ul>
+ * <strong> Important note: </strong> only apps with
+ * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} should use this method.
+ * Otherwise, a {@code SecurityException} will be thrown.
*
* <p>
* Equivalent to {@link #getDrawable(int)}.
@@ -1268,7 +1250,7 @@
* instead the default wallpaper is returned
* (some versions of T may throw a {@code SecurityException}).</li>
* <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
+ * and will always throw a {@code SecurityException}.</li>
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
@@ -1290,19 +1272,9 @@
}
/**
- * <strong> Important note: </strong>
- * <ul>
- * <li>Up to version S, this method requires the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
- * <li>Starting in T, directly accessing the wallpaper is not possible anymore,
- * instead the default system wallpaper is returned
- * (some versions of T may throw a {@code SecurityException}).</li>
- * <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
- * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
- * can still access the real wallpaper on all versions. </li>
- * </ul>
- * <br>
+ * <strong> Important note: </strong> only apps with
+ * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} should use this method.
+ * Otherwise, a {@code SecurityException} will be thrown.
*
* Like {@link #getDrawable(int)}, but the returned Drawable has a number
* of limitations to reduce its overhead as much as possible. It will
@@ -1334,18 +1306,9 @@
}
/**
- * <strong> Important note: </strong>
- * <ul>
- * <li>Up to version S, this method requires the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
- * <li>Starting in T, directly accessing the wallpaper is not possible anymore,
- * instead the default system wallpaper is returned
- * (some versions of T may throw a {@code SecurityException}).</li>
- * <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
- * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
- * can still access the real wallpaper on all versions. </li>
- * </ul>
+ * <strong> Important note: </strong> only apps with
+ * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} should use this method.
+ * Otherwise, a {@code SecurityException} will be thrown.
*
* <p>
* Equivalent to {@link #getFastDrawable()}.
@@ -1364,18 +1327,9 @@
}
/**
- * <strong> Important note: </strong>
- * <ul>
- * <li>Up to version S, this method requires the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
- * <li>Starting in T, directly accessing the wallpaper is not possible anymore,
- * instead the default system wallpaper is returned
- * (some versions of T may throw a {@code SecurityException}).</li>
- * <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
- * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
- * can still access the real wallpaper on all versions. </li>
- * </ul>
+ * <strong> Important note: </strong> only apps with
+ * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
+ * should use this method. Otherwise, a {@code SecurityException} will be thrown.
*
* <p>
* Equivalent to {@link #getFastDrawable(int)}.
@@ -1562,7 +1516,7 @@
* instead the default system wallpaper is returned
* (some versions of T may throw a {@code SecurityException}).</li>
* <li>From version U, this method should not be used
- * and will always throw a @code SecurityException}.</li>
+ * and will always throw a {@code SecurityException}.</li>
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
@@ -2475,19 +2429,38 @@
}
/**
- * Reset all wallpaper to the factory default.
+ * Reset all wallpaper to the factory default. As opposed to {@link #clear()}, if the device
+ * is configured to have a live wallpaper by default, apply it.
*
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*/
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clearWallpaper() {
+ if (isLockscreenLiveWallpaperEnabled()) {
+ clearWallpaper(FLAG_LOCK | FLAG_SYSTEM, mContext.getUserId());
+ return;
+ }
clearWallpaper(FLAG_LOCK, mContext.getUserId());
clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
}
/**
- * Clear the wallpaper for a specific user. The caller must hold the
+ * Clear the wallpaper for a specific user.
+ * <ul>
+ * <li> When called with {@code which=}{@link #FLAG_LOCK}, clear the lockscreen wallpaper.
+ * The home screen wallpaper will become visible on the lock screen. </li>
+ *
+ * <li> When called with {@code which=}{@link #FLAG_SYSTEM}, revert the home screen
+ * wallpaper to default. The lockscreen wallpaper will be unchanged: if the previous
+ * wallpaper was shared between home and lock screen, it will become lock screen only. </li>
+ *
+ * <li> When called with {@code which=}({@link #FLAG_LOCK} | {@link #FLAG_SYSTEM}), put the
+ * default wallpaper on both home and lock screen, removing any user defined wallpaper.</li>
+ * </ul>
+ * </p>
+ *
+ * The caller must hold the
* INTERACT_ACROSS_USERS_FULL permission to clear another user's
* wallpaper, and must hold the SET_WALLPAPER permission in all
* circumstances.
@@ -2792,8 +2765,9 @@
/**
* Remove any currently set system wallpaper, reverting to the system's built-in
- * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
- * is broadcast.
+ * wallpaper. As opposed to {@link #clearWallpaper()}, this method always set a static wallpaper
+ * with the default image, even if the device is configured to have a live wallpaper by default.
+ * On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
*
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
@@ -2808,9 +2782,14 @@
/**
* Remove one or more currently set wallpapers, reverting to the system default
- * display for each one. If {@link #FLAG_SYSTEM} is set in the {@code which}
- * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
- * upon success.
+ * display for each one. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
+ * is broadcast.
+ * <ul>
+ * <li> If {@link #FLAG_SYSTEM} is set in the {@code which} parameter, put the default
+ * wallpaper on both home and lock screen, removing any user defined wallpaper. </li>
+ * <li> When called with {@code which=}{@link #FLAG_LOCK}, clear the lockscreen wallpaper.
+ * The home screen wallpaper will become visible on the lock screen. </li>
+ * </ul>
*
* @param which A bitwise combination of {@link #FLAG_SYSTEM} or
* {@link #FLAG_LOCK}
@@ -2820,6 +2799,7 @@
public void clear(@SetWallpaperFlags int which) throws IOException {
if ((which & FLAG_SYSTEM) != 0) {
clear();
+ if (isLockscreenLiveWallpaperEnabled()) return;
}
if ((which & FLAG_LOCK) != 0) {
clearWallpaper(FLAG_LOCK, mContext.getUserId());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b2a9230..da5e40a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11369,7 +11369,8 @@
* @throws SecurityException if the caller is not a profile owner on an organization-owned
* managed profile.
* @throws IllegalStateException if called after the device setup has been completed.
- * @throws UnsupportedOperationException if the api is not enabled.
+ * @throws UnsupportedOperationException if managed subscriptions policy is not explicitly
+ * enabled by the device policy management role holder during device setup.
* @see ManagedSubscriptionsPolicy
*/
public void setManagedSubscriptionsPolicy(@Nullable ManagedSubscriptionsPolicy policy) {
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index 3fefe4b..ed53967 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -135,6 +135,10 @@
dest.writeArraySet(mSsids);
}
+ /**
+ * Two instances of WifiSsidPolicy is considered equal if they have
+ * the same WifiSsidPolicyType and the same set of WifiSsids
+ */
@Override
public boolean equals(Object thatObject) {
if (this == thatObject) {
@@ -147,6 +151,9 @@
return mPolicyType == that.mPolicyType && Objects.equals(mSsids, that.mSsids);
}
+ /**
+ * Returns the hash code value of WifiSsidPolicyType and WifiSsid set
+ */
@Override
public int hashCode() {
return Objects.hash(mPolicyType, mSsids);
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index 4da3c18..5e10a57 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -37,16 +37,16 @@
* @param key a key that uniquely identifies the drawable resource
* @param resources a Resources object from which to create new instances.
* @param theme the theme where the resource will be used
- * @return an Entry wrapping a new instance of the resource, or {@code null} if not in
+ * @return a new instance of the resource, or {@code null} if not in
* the cache
*/
- public Entry<T> getInstance(long key, Resources resources, Resources.Theme theme) {
- final Entry<ConstantState<T>> e = get(key, theme);
- if (e.hasValue()) {
- return new Entry<>(e.getValue().newInstance(resources, theme), e.getGeneration());
+ public T getInstance(long key, Resources resources, Resources.Theme theme) {
+ final ConstantState<T> entry = get(key, theme);
+ if (entry != null) {
+ return entry.newInstance(resources, theme);
}
- return new Entry<>(null, e.getGeneration());
+ return null;
}
@Override
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index b51d14a..d0ebe33 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -40,32 +40,14 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
- final Entry<Drawable.ConstantState> entry = get(key, theme);
- if (entry.getValue() != null) {
- return entry.getValue().newDrawable(resources, theme);
+ final Drawable.ConstantState entry = get(key, theme);
+ if (entry != null) {
+ return entry.newDrawable(resources, theme);
}
return null;
}
- /**
- * If the resource is cached, creates and returns a new instance of it.
- *
- * @param key a key that uniquely identifies the drawable resource
- * @param resources a Resources object from which to create new instances.
- * @param theme the theme where the resource will be used
- * @return an Entry wrapping a a new instance of the resource, or {@code null} if not in
- * the cache
- */
- public Entry<Drawable> getDrawable(long key, Resources resources, Resources.Theme theme) {
- final Entry<Drawable.ConstantState> e = get(key, theme);
- if (e.hasValue()) {
- return new Entry<>(e.getValue().newDrawable(resources, theme), e.getGeneration());
- }
-
- return new Entry<>(null, e.getGeneration());
- }
-
@Override
public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 25154d5..61d5aa6 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,6 +27,7 @@
import android.annotation.RawRes;
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
+import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
@@ -408,17 +409,24 @@
if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
if (locales.size() > 1) {
- // The LocaleList has changed. We must query the AssetManager's available
- // Locales and figure out the best matching Locale in the new LocaleList.
- String[] availableLocales = mAssets.getNonSystemLocales();
- if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
- // No app defined locales, so grab the system locales.
- availableLocales = mAssets.getLocales();
+ String[] availableLocales;
+
+ LocaleList localeList = ResourcesManager.getInstance().getLocaleList();
+ if (!localeList.isEmpty()) {
+ availableLocales = localeList.toLanguageTags().split(",");
+ } else {
+ // The LocaleList has changed. We must query the AssetManager's
+ // available Locales and figure out the best matching Locale in the new
+ // LocaleList.
+ availableLocales = mAssets.getNonSystemLocales();
if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
- availableLocales = null;
+ // No app defined locales, so grab the system locales.
+ availableLocales = mAssets.getLocales();
+ if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
+ availableLocales = null;
+ }
}
}
-
if (availableLocales != null) {
final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
availableLocales);
@@ -650,21 +658,16 @@
key = (((long) value.assetCookie) << 32) | value.data;
}
- int cacheGeneration;
+ int cacheGeneration = caches.getGeneration();
// First, check whether we have a cached version of this drawable
// that was inflated against the specified theme. Skip the cache if
// we're currently preloading or we're not using the cache.
if (!mPreloading && useCache) {
- final ThemedResourceCache.Entry<Drawable> cachedDrawable =
- caches.getDrawable(key, wrapper, theme);
- if (cachedDrawable.hasValue()) {
- cachedDrawable.getValue().setChangingConfigurations(
- value.changingConfigurations);
- return cachedDrawable.getValue();
+ Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+ if (cachedDrawable != null) {
+ cachedDrawable.setChangingConfigurations(value.changingConfigurations);
+ return cachedDrawable;
}
- cacheGeneration = cachedDrawable.getGeneration();
- } else {
- cacheGeneration = ThemedResourceCache.UNDEFINED_GENERATION;
}
// Next, check preloaded drawables. Preloaded drawables may contain
@@ -1009,16 +1012,15 @@
TypedValue value, int id) {
final long key = (((long) value.assetCookie) << 32) | value.data;
final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
- ThemedResourceCache.Entry<ComplexColor> complexColorEntry =
- cache.getInstance(key, wrapper, theme);
- if (complexColorEntry.hasValue()) {
- return complexColorEntry.getValue();
+ ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+ if (complexColor != null) {
+ return complexColor;
}
+ int cacheGeneration = cache.getGeneration();
final android.content.res.ConstantState<ComplexColor> factory =
sPreloadedComplexColors.get(key);
- ComplexColor complexColor = null;
if (factory != null) {
complexColor = factory.newInstance(wrapper, theme);
}
@@ -1035,8 +1037,7 @@
sPreloadedComplexColors.put(key, complexColor.getConstantState());
}
} else {
- cache.put(key, theme, complexColor.getConstantState(),
- complexColorEntry.getGeneration());
+ cache.put(key, theme, complexColor.getConstantState(), cacheGeneration);
}
}
return complexColor;
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index e7fd275..a7cd168 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -41,29 +41,6 @@
private int mGeneration;
- public static class Entry<S> {
- private S mValue;
- private int mGeneration;
-
-
- public S getValue() {
- return mValue;
- }
-
- public boolean hasValue() {
- return mValue != null;
- }
-
- public int getGeneration() {
- return mGeneration;
- }
-
- Entry(S value, int generation) {
- this.mValue = value;
- this.mGeneration = generation;
- }
- }
-
/**
* Adds a new theme-dependent entry to the cache.
*
@@ -109,6 +86,15 @@
}
/**
+ * Returns the current generation of the cache
+ *
+ * @return The current generation
+ */
+ public int getGeneration() {
+ return mGeneration;
+ }
+
+ /**
* Returns an entry from the cache.
*
* @param key a key that uniquely identifies the entry
@@ -116,7 +102,7 @@
* @return a cached entry, or {@code null} if not in the cache
*/
@Nullable
- public Entry get(long key, @Nullable Theme theme) {
+ public T get(long key, @Nullable Theme theme) {
// The themed (includes null-themed) and unthemed caches are mutually
// exclusive, so we'll give priority to whichever one we think we'll
// hit first. Since most of the framework drawables are themed, that's
@@ -126,7 +112,7 @@
if (themedEntries != null) {
final WeakReference<T> themedEntry = themedEntries.get(key);
if (themedEntry != null) {
- return new Entry(themedEntry.get(), mGeneration);
+ return themedEntry.get();
}
}
@@ -134,14 +120,15 @@
if (unthemedEntries != null) {
final WeakReference<T> unthemedEntry = unthemedEntries.get(key);
if (unthemedEntry != null) {
- return new Entry(unthemedEntry.get(), mGeneration);
+ return unthemedEntry.get();
}
}
}
- return new Entry(null, mGeneration);
+ return null;
}
+
/**
* Prunes cache entries that have been invalidated by a configuration
* change.
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index 0311da4..4403251 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -73,7 +73,7 @@
private final int mProductId;
/** Currently supported Layout types in the KCM files */
- private enum LayoutType {
+ public enum LayoutType {
UNDEFINED(0, LAYOUT_TYPE_UNDEFINED),
QWERTY(1, LAYOUT_TYPE_QWERTY),
QWERTZ(2, LAYOUT_TYPE_QWERTZ),
@@ -88,9 +88,11 @@
private final int mValue;
private final String mName;
private static final Map<Integer, LayoutType> VALUE_TO_ENUM_MAP = new HashMap<>();
+ private static final Map<String, LayoutType> NAME_TO_ENUM_MAP = new HashMap<>();
static {
for (LayoutType type : LayoutType.values()) {
VALUE_TO_ENUM_MAP.put(type.mValue, type);
+ NAME_TO_ENUM_MAP.put(type.mName, type);
}
}
@@ -110,6 +112,25 @@
private String getName() {
return mName;
}
+
+ /**
+ * Returns enum value for provided layout type
+ * @param layoutName name of the layout type
+ * @return int value corresponding to the LayoutType enum that matches the layout name.
+ * (LayoutType.UNDEFINED if no match found)
+ */
+ public static int getLayoutTypeEnumValue(String layoutName) {
+ return NAME_TO_ENUM_MAP.getOrDefault(layoutName, UNDEFINED).getValue();
+ }
+
+ /**
+ * Returns name for provided layout type enum value
+ * @param enumValue value representation for LayoutType enum
+ * @return Layout name corresponding to the enum value (LAYOUT_TYPE_UNDEFINED if not found)
+ */
+ public static String getLayoutNameFromValue(int enumValue) {
+ return VALUE_TO_ENUM_MAP.getOrDefault(enumValue, UNDEFINED).getName();
+ }
}
@NonNull
diff --git a/core/java/android/net/ITetheringStatsProvider.aidl b/core/java/android/net/ITetheringStatsProvider.aidl
deleted file mode 100644
index da0bf4c..0000000
--- a/core/java/android/net/ITetheringStatsProvider.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.NetworkStats;
-
-/**
- * Interface for NetworkManagementService to query tethering statistics and set data limits.
- *
- * TODO: this does not really need to be an interface since Tethering runs in the same process
- * as NetworkManagementService. Consider refactoring Tethering to use direct access to
- * NetworkManagementService instead of using INetworkManagementService, and then deleting this
- * interface.
- *
- * @hide
- */
-interface ITetheringStatsProvider {
- // Returns cumulative statistics for all tethering sessions since boot, on all upstreams.
- // @code {how} is one of the NetworkStats.STATS_PER_* constants. If {@code how} is
- // {@code STATS_PER_IFACE}, the provider should not include any traffic that is already
- // counted by kernel interface counters.
- NetworkStats getTetherStats(int how);
-
- // Sets the interface quota for the specified upstream interface. This is defined as the number
- // of bytes, starting from zero and counting from now, after which data should stop being
- // forwarded to/from the specified upstream. A value of QUOTA_UNLIMITED means there is no limit.
- void setInterfaceQuota(String iface, long quotaBytes);
-
- // Indicates that no data usage limit is set.
- const int QUOTA_UNLIMITED = -1;
-}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index ba4f82d..70de477 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -882,10 +882,11 @@
}
static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
return new OpaqueUri(
- parcel.readString8(),
- Part.readFrom(parcel),
- Part.readFrom(parcel)
+ stringUri.parseScheme(),
+ stringUri.getSsp(),
+ stringUri.getFragmentPart()
);
}
@@ -895,9 +896,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- ssp.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
@@ -1196,22 +1195,25 @@
Part query, Part fragment) {
this.scheme = scheme;
this.authority = Part.nonNull(authority);
- this.path = path == null ? PathPart.NULL : path;
+ this.path = generatePath(path);
this.query = Part.nonNull(query);
this.fragment = Part.nonNull(fragment);
}
- static Uri readFrom(Parcel parcel) {
- final String scheme = parcel.readString8();
- final Part authority = Part.readFrom(parcel);
+ private PathPart generatePath(PathPart originalPath) {
// In RFC3986 the path should be determined based on whether there is a scheme or
// authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
final boolean hasSchemeOrAuthority =
(scheme != null && scheme.length() > 0) || !authority.isEmpty();
- final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel);
- final Part query = Part.readFrom(parcel);
- final Part fragment = Part.readFrom(parcel);
- return new HierarchicalUri(scheme, authority, path, query, fragment);
+ final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
+ : originalPath;
+ return newPath == null ? PathPart.NULL : newPath;
+ }
+
+ static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
+ return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(),
+ stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart());
}
public int describeContents() {
@@ -1220,11 +1222,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- authority.writeTo(parcel);
- path.writeTo(parcel);
- query.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
@@ -1994,21 +1992,14 @@
*/
static abstract class AbstractPart {
- // Possible values of mCanonicalRepresentation.
- static final int REPRESENTATION_ENCODED = 1;
- static final int REPRESENTATION_DECODED = 2;
-
volatile String encoded;
volatile String decoded;
- private final int mCanonicalRepresentation;
AbstractPart(String encoded, String decoded) {
if (encoded != NotCachedHolder.NOT_CACHED) {
- this.mCanonicalRepresentation = REPRESENTATION_ENCODED;
this.encoded = encoded;
this.decoded = NotCachedHolder.NOT_CACHED;
} else if (decoded != NotCachedHolder.NOT_CACHED) {
- this.mCanonicalRepresentation = REPRESENTATION_DECODED;
this.encoded = NotCachedHolder.NOT_CACHED;
this.decoded = decoded;
} else {
@@ -2023,24 +2014,6 @@
boolean hasDecoded = decoded != NotCachedHolder.NOT_CACHED;
return hasDecoded ? decoded : (decoded = decode(encoded));
}
-
- final void writeTo(Parcel parcel) {
- final String canonicalValue;
- if (mCanonicalRepresentation == REPRESENTATION_ENCODED) {
- canonicalValue = encoded;
- } else if (mCanonicalRepresentation == REPRESENTATION_DECODED) {
- canonicalValue = decoded;
- } else {
- throw new IllegalArgumentException("Unknown representation: "
- + mCanonicalRepresentation);
- }
- if (canonicalValue == NotCachedHolder.NOT_CACHED) {
- throw new AssertionError("Canonical value not cached ("
- + mCanonicalRepresentation + ")");
- }
- parcel.writeInt(mCanonicalRepresentation);
- parcel.writeString8(canonicalValue);
- }
}
/**
@@ -2069,20 +2042,6 @@
return hasEncoded ? encoded : (encoded = encode(decoded));
}
- static Part readFrom(Parcel parcel) {
- int representation = parcel.readInt();
- String value = parcel.readString8();
- switch (representation) {
- case REPRESENTATION_ENCODED:
- return fromEncoded(value);
- case REPRESENTATION_DECODED:
- return fromDecoded(value);
- default:
- throw new IllegalArgumentException("Unknown representation: "
- + representation);
- }
- }
-
/**
* Returns given part or {@link #NULL} if the given part is null.
*/
@@ -2258,23 +2217,6 @@
return appendEncodedSegment(oldPart, encoded);
}
- static PathPart readFrom(Parcel parcel) {
- int representation = parcel.readInt();
- switch (representation) {
- case REPRESENTATION_ENCODED:
- return fromEncoded(parcel.readString8());
- case REPRESENTATION_DECODED:
- return fromDecoded(parcel.readString8());
- default:
- throw new IllegalArgumentException("Unknown representation: " + representation);
- }
- }
-
- static PathPart readFrom(boolean hasSchemeOrAuthority, Parcel parcel) {
- final PathPart path = readFrom(parcel);
- return hasSchemeOrAuthority ? makeAbsolute(path) : path;
- }
-
/**
* Creates a path from the encoded string.
*
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 40f7533..ed14652 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,7 +19,6 @@
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
-import android.net.ITetheringStatsProvider;
import android.net.Network;
import android.net.NetworkStats;
import android.net.RouteInfo;
@@ -144,14 +143,6 @@
void startTethering(in String[] dhcpRanges);
/**
- * Start tethering services with the specified dhcp server range and
- * DNS proxy config.
- * {@code boolean} is used to control legacy DNS proxy server.
- * {@code String[]} is a set of start end pairs defining the ranges.
- */
- void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, in String[] dhcpRanges);
-
- /**
* Stop currently running tethering services
*/
@UnsupportedAppUsage
@@ -182,23 +173,6 @@
String[] listTetheredInterfaces();
/**
- * Returns the list of DNS forwarders (in order of priority)
- */
- String[] getDnsForwarders();
-
- /**
- * Enables unidirectional packet forwarding from {@code fromIface} to
- * {@code toIface}.
- */
- void startInterfaceForwarding(String fromIface, String toIface);
-
- /**
- * Disables unidirectional packet forwarding from {@code fromIface} to
- * {@code toIface}.
- */
- void stopInterfaceForwarding(String fromIface, String toIface);
-
- /**
* Enables Network Address Translation between two interfaces.
* The address and netmask of the external interface is used for
* the NAT'ed network.
@@ -213,42 +187,10 @@
void disableNat(String internalInterface, String externalInterface);
/**
- * Registers a {@code ITetheringStatsProvider} to provide tethering statistics.
- * All registered providers will be called in order, and their results will be added together.
- * Netd is always registered as a tethering stats provider.
- */
- void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name);
-
- /**
- * Unregisters a previously-registered {@code ITetheringStatsProvider}.
- */
- void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
-
- /**
- * Reports that a tethering provider has reached a data limit.
- *
- * Currently triggers a global alert, which causes NetworkStatsService to poll counters and
- * re-evaluate data usage.
- *
- * This does not take an interface name because:
- * 1. The tethering offload stats provider cannot reliably determine the interface on which the
- * limit was reached, because the HAL does not provide it.
- * 2. Firing an interface-specific alert instead of a global alert isn't really useful since in
- * all cases of interest, the system responds to both in the same way - it polls stats, and
- * then notifies NetworkPolicyManagerService of the fact.
- */
- void tetherLimitReached(ITetheringStatsProvider provider);
-
- /**
** DATA USAGE RELATED
**/
/**
- * Return summary of network statistics all tethering interfaces.
- */
- NetworkStats getNetworkStatsTethering(int how);
-
- /**
* Set quota for an interface.
*/
void setInterfaceQuota(String iface, long quotaBytes);
@@ -269,11 +211,6 @@
void removeInterfaceAlert(String iface);
/**
- * Set alert across all interfaces.
- */
- void setGlobalAlert(long alertBytes);
-
- /**
* Control network activity of a UID over interfaces with a quota limit.
*/
void setUidOnMeteredNetworkDenylist(int uid, boolean enable);
@@ -291,7 +228,6 @@
void setFirewallEnabled(boolean enabled);
boolean isFirewallEnabled();
- void setFirewallInterfaceRule(String iface, boolean allow);
void setFirewallUidRule(int chain, int uid, int rule);
void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
void setFirewallChainEnabled(int chain, boolean enable);
@@ -306,10 +242,6 @@
*/
void denyProtect(int uid);
- void addInterfaceToLocalNetwork(String iface, in List<RouteInfo> routes);
- void removeInterfaceFromLocalNetwork(String iface);
- int removeRoutesFromLocalNetwork(in List<RouteInfo> routes);
-
@EnforcePermission("OBSERVE_NETWORK_POLICY")
boolean isNetworkRestricted(int uid);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f20854b..c6b9d20 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -190,8 +190,7 @@
/**
* Wake lock flag: Turn the screen on when the wake lock is acquired.
* <p>
- * This flag requires {@link android.Manifest.permission#TURN_SCREEN_ON} for apps targeting
- * Android version {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and higher.
+ * This flag will require {@link android.Manifest.permission#TURN_SCREEN_ON} in future releases.
* </p><p>
* Normally wake locks don't actually wake the device, they just cause the screen to remain on
* once it's already on. This flag will cause the device to wake up when the wake lock is
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index ef39010..0527ed6 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -606,12 +606,9 @@
@Override
public boolean equals(@Nullable Object obj) {
- try {
- if (obj != null) {
- UserHandle other = (UserHandle)obj;
- return mHandle == other.mHandle;
- }
- } catch (ClassCastException ignore) {
+ if (obj instanceof UserHandle) {
+ UserHandle other = (UserHandle) obj;
+ return mHandle == other.mHandle;
}
return false;
}
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index d22faa8..bf22dcc 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -5,16 +5,15 @@
# Android Storage Team
alukin@google.com
ankitavyas@google.com
-corinac@google.com
dipankarb@google.com
gargshivam@google.com
krishang@google.com
riyaghai@google.com
sahanas@google.com
sergeynv@google.com
+shikhamalhotra@google.com
shubhisaxena@google.com
tylersaunders@google.com
maco@google.com
nandana@google.com
-narayan@google.com
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index b0dda6f..e256ea0 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -177,6 +177,13 @@
public static final long CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS = 146211400;
/**
+ * Whether to use the new {@link com.android.server.permission.access.AccessCheckingService}.
+ *
+ * @hide
+ */
+ public static final boolean USE_ACCESS_CHECKING_SERVICE = false;
+
+ /**
* The time to wait in between refreshing the exempted indicator role packages
*/
private static final long EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS = 15000;
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 931adb5..ef274a5 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -23,6 +23,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Application.ActivityLifecycleCallbacks;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -535,7 +536,11 @@
return null;
}
try {
- mContext.startIntentSender(intent, null, 0, 0, 0);
+ ActivityOptions activityOptions = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ mContext.startIntentSender(intent, null, 0, 0, 0,
+ activityOptions.toBundle());
return new PrintJob(printJob, this);
} catch (SendIntentException sie) {
Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 4a848dd..8cf2ce4 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -123,6 +123,12 @@
*/
public static final @RequestFlags int FLAG_PCC_DETECTION = 0x200;
+ /**
+ * Indicate whether the screen has credman field
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD = 0x400;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -236,7 +242,8 @@
FLAG_SUPPORTS_FILL_DIALOG,
FLAG_IME_SHOWING,
FLAG_RESET_FILL_DIALOG_STATE,
- FLAG_PCC_DETECTION
+ FLAG_PCC_DETECTION,
+ FLAG_SCREEN_HAS_CREDMAN_FIELD
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -268,6 +275,8 @@
return "FLAG_RESET_FILL_DIALOG_STATE";
case FLAG_PCC_DETECTION:
return "FLAG_PCC_DETECTION";
+ case FLAG_SCREEN_HAS_CREDMAN_FIELD:
+ return "FLAG_SCREEN_HAS_CREDMAN_FIELD";
default: return Integer.toHexString(value);
}
}
@@ -284,10 +293,15 @@
* include contexts from requests whose {@link SaveInfo} had the
* {@link SaveInfo#FLAG_DELAY_SAVE} flag.
* @param hints
- * Autofill Provider should return data for the autofill hints requested here,
+ * Sends a list of datatypes for the Autofill Provider.
+ *
+ * If this is populated, Autofill Provider should return data
+ * for the autofill hints requested here,
* even though the Autofill Provider may not have detected these types.
* The hints would be part of HintConstants:
* https://developer.android.com/reference/androidx/autofill/HintConstants
+ *
+ * This is populated if the platform's field detection is enabled.
* @param clientState
* Gets the latest client state bundle set by the service in a
* {@link FillResponse.Builder#setClientState(Bundle) fill response}.
@@ -355,7 +369,8 @@
| FLAG_SUPPORTS_FILL_DIALOG
| FLAG_IME_SHOWING
| FLAG_RESET_FILL_DIALOG_STATE
- | FLAG_PCC_DETECTION);
+ | FLAG_PCC_DETECTION
+ | FLAG_SCREEN_HAS_CREDMAN_FIELD);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -383,10 +398,15 @@
}
/**
- * Autofill Provider should return data for the autofill hints requested here,
+ * Sends a list of datatypes for the Autofill Provider.
+ *
+ * If this is populated, Autofill Provider should return data
+ * for the autofill hints requested here,
* even though the Autofill Provider may not have detected these types.
* The hints would be part of HintConstants:
* https://developer.android.com/reference/androidx/autofill/HintConstants
+ *
+ * This is populated if the platform's field detection is enabled.
*/
@DataClass.Generated.Member
public @NonNull List<String> getHints() {
@@ -536,7 +556,8 @@
| FLAG_SUPPORTS_FILL_DIALOG
| FLAG_IME_SHOWING
| FLAG_RESET_FILL_DIALOG_STATE
- | FLAG_PCC_DETECTION);
+ | FLAG_PCC_DETECTION
+ | FLAG_SCREEN_HAS_CREDMAN_FIELD);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -558,10 +579,10 @@
};
@DataClass.Generated(
- time = 1675711417112L,
+ time = 1682097266850L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index f0140e1..7fa0ac8 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -37,6 +37,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
@@ -140,10 +141,9 @@
private long mCallerMismatchTimeout = 1000;
private long mLastCallerMismatchLog;
- /**
- * Binder that receives calls from the system server.
- */
- private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
+ /** Binder that receives calls from the system server in the content capture flow. */
+ private final IContentCaptureService mContentCaptureServerInterface =
+ new IContentCaptureService.Stub() {
@Override
public void onConnected(IBinder callback, boolean verbose, boolean debug) {
@@ -199,10 +199,24 @@
}
};
- /**
- * Binder that receives calls from the app.
- */
- private final IContentCaptureDirectManager mClientInterface =
+ /** Binder that receives calls from the system server in the content protection flow. */
+ private final IContentProtectionService mContentProtectionServerInterface =
+ new IContentProtectionService.Stub() {
+
+ @Override
+ public void onLoginDetected(
+ @SuppressWarnings("rawtypes") ParceledListSlice events) {
+ mHandler.sendMessage(
+ obtainMessage(
+ ContentCaptureService::handleOnLoginDetected,
+ ContentCaptureService.this,
+ Binder.getCallingUid(),
+ events));
+ }
+ };
+
+ /** Binder that receives calls from the app in the content capture flow. */
+ private final IContentCaptureDirectManager mContentCaptureClientInterface =
new IContentCaptureDirectManager.Stub() {
@Override
@@ -232,9 +246,19 @@
@Override
public final IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mServerInterface.asBinder();
+ return mContentCaptureServerInterface.asBinder();
}
- Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+ if (PROTECTION_SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mContentProtectionServerInterface.asBinder();
+ }
+ Log.w(
+ TAG,
+ "Tried to bind to wrong intent (should be "
+ + SERVICE_INTERFACE
+ + " or "
+ + PROTECTION_SERVICE_INTERFACE
+ + "): "
+ + intent);
return null;
}
@@ -468,7 +492,7 @@
} else {
stateFlags |= ContentCaptureSession.STATE_DISABLED;
}
- setClientState(clientReceiver, stateFlags, mClientInterface.asBinder());
+ setClientState(clientReceiver, stateFlags, mContentCaptureClientInterface.asBinder());
}
private void handleSendEvents(int uid,
@@ -536,6 +560,18 @@
writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason);
}
+ private void handleOnLoginDetected(
+ int uid, @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) {
+ if (uid != Process.SYSTEM_UID) {
+ Log.e(TAG, "handleOnLoginDetected() not allowed for uid: " + uid);
+ return;
+ }
+ List<ContentCaptureEvent> events = parceledEvents.getList();
+ int sessionIdInt = events.isEmpty() ? NO_SESSION_ID : events.get(0).getSessionId();
+ ContentCaptureSessionId sessionId = new ContentCaptureSessionId(sessionIdInt);
+ events.forEach(event -> onContentCaptureEvent(sessionId, event));
+ }
+
private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
}
diff --git a/core/java/android/service/contentcapture/IContentProtectionService.aidl b/core/java/android/service/contentcapture/IContentProtectionService.aidl
new file mode 100644
index 0000000..4a13c3f
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentProtectionService.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 android.service.contentcapture;
+
+import android.content.pm.ParceledListSlice;
+import android.view.contentcapture.ContentCaptureEvent;
+
+/**
+ * Interface from the system server to the content protection service.
+ *
+ * @hide
+ */
+oneway interface IContentProtectionService {
+
+ void onLoginDetected(in ParceledListSlice events);
+}
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 5469916..9a02b74b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -71,13 +71,7 @@
@Override
public void wakeUp() {
- mService.wakeUp(this, () -> {
- try {
- mDreamOverlayCallback.onWakeUpComplete();
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify dream of wakeUp", e);
- }
- });
+ mService.wakeUp(this);
}
@Override
@@ -125,14 +119,14 @@
mCurrentClient = null;
}
- private void wakeUp(OverlayClient client, Runnable callback) {
+ private void wakeUp(OverlayClient client) {
// Run on executor as this is a binder call from OverlayClient.
mExecutor.execute(() -> {
if (mCurrentClient != client) {
return;
}
- onWakeUp(callback);
+ onWakeUp();
});
}
@@ -190,19 +184,10 @@
/**
* This method is overridden by implementations to handle when the dream has been requested
- * to wakeup. This allows any overlay animations to run. By default, the method will invoke
- * the callback immediately.
- *
- * This callback will be run on the {@link Executor} provided in the constructor if provided, or
- * on the main executor if none was provided.
- *
- * @param onCompleteCallback The callback to trigger to notify the dream service that the
- * overlay has completed waking up.
+ * to wakeup.
* @hide
*/
- public void onWakeUp(@NonNull Runnable onCompleteCallback) {
- onCompleteCallback.run();
- }
+ public void onWakeUp() {}
/**
* This method is overridden by implementations to handle when the dream has ended. There may
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3a32352..cd57de5 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -249,13 +249,6 @@
// Simply finish dream when exit is requested.
mHandler.post(() -> finish());
}
-
- @Override
- public void onWakeUpComplete() {
- // Finish the dream once overlay animations are complete. Execute on handler since
- // this is coming in on the overlay binder.
- mHandler.post(() -> finish());
- }
};
@@ -923,6 +916,7 @@
overlay.wakeUp();
} catch (RemoteException e) {
Slog.e(TAG, "Error waking the overlay service", e);
+ } finally {
finish();
}
});
diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
index 4ad63f1..ec76a33 100644
--- a/core/java/android/service/dreams/IDreamOverlayCallback.aidl
+++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
@@ -28,7 +28,4 @@
* Invoked to request the dream exit.
*/
void onExitRequested();
-
- /** Invoked when the dream overlay wakeUp animation is complete. */
- void onWakeUpComplete();
}
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index a853714..75640bd 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -16,32 +16,117 @@
package android.service.notification;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+
+import java.nio.ByteBuffer;
/**
+ * Represents an update to notification rankings.
* @hide
*/
+@SuppressLint({"ParcelNotFinal", "ParcelCreator"})
+@TestApi
public class NotificationRankingUpdate implements Parcelable {
private final NotificationListenerService.RankingMap mRankingMap;
+ // The ranking map is stored in shared memory when parceled, for sending across the binder.
+ // This is done because the ranking map can grow large if there are many notifications.
+ private SharedMemory mRankingMapFd = null;
+ private final String mSharedMemoryName = "NotificationRankingUpdatedSharedMemory";
+
+ /**
+ * @hide
+ */
public NotificationRankingUpdate(NotificationListenerService.Ranking[] rankings) {
mRankingMap = new NotificationListenerService.RankingMap(rankings);
}
+ /**
+ * @hide
+ */
public NotificationRankingUpdate(Parcel in) {
- mRankingMap = in.readParcelable(getClass().getClassLoader(), android.service.notification.NotificationListenerService.RankingMap.class);
+ if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
+ SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
+ // Recover the ranking map from the SharedMemory and store it in mapParcel.
+ final Parcel mapParcel = Parcel.obtain();
+ ByteBuffer buffer = null;
+ try {
+ // The ranking map should be stored in shared memory when it is parceled, so we
+ // unwrap the SharedMemory object.
+ mRankingMapFd = in.readParcelable(getClass().getClassLoader(), SharedMemory.class);
+
+ // In the case that the ranking map can't be read, readParcelable may return null.
+ // In this case, we set mRankingMap to null;
+ if (mRankingMapFd == null) {
+ mRankingMap = null;
+ return;
+ }
+ // We only need read-only access to the shared memory region.
+ buffer = mRankingMapFd.mapReadOnly();
+ if (buffer == null) {
+ mRankingMap = null;
+ return;
+ }
+ byte[] payload = new byte[buffer.remaining()];
+ buffer.get(payload);
+ mapParcel.unmarshall(payload, 0, payload.length);
+ mapParcel.setDataPosition(0);
+
+ mRankingMap = mapParcel.readParcelable(getClass().getClassLoader(),
+ android.service.notification.NotificationListenerService.RankingMap.class);
+ } catch (ErrnoException e) {
+ // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
+ // avoid crashes; change to Log.wtf.
+ throw new RuntimeException(e);
+ } finally {
+ mapParcel.recycle();
+ if (buffer != null) {
+ mRankingMapFd.unmap(buffer);
+ }
+ }
+ } else {
+ mRankingMap = in.readParcelable(getClass().getClassLoader(),
+ android.service.notification.NotificationListenerService.RankingMap.class);
+ }
}
+ /**
+ * Confirms that the SharedMemory file descriptor is closed. Should only be used for testing.
+ * @hide
+ */
+ @TestApi
+ public final boolean isFdNotNullAndClosed() {
+ return mRankingMapFd != null && mRankingMapFd.getFd() == -1;
+ }
+
+ /**
+ * @hide
+ */
public NotificationListenerService.RankingMap getRankingMap() {
return mRankingMap;
}
+ /**
+ * @hide
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * @hide
+ */
@Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
@@ -51,11 +136,51 @@
return mRankingMap.equals(other.mRankingMap);
}
+ /**
+ * @hide
+ */
@Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(mRankingMap, flags);
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
+ SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
+ final Parcel mapParcel = Parcel.obtain();
+ try {
+ // Parcels the ranking map and measures its size.
+ mapParcel.writeParcelable(mRankingMap, flags);
+ int mapSize = mapParcel.dataSize();
+
+ // Creates a new SharedMemory object with enough space to hold the ranking map.
+ SharedMemory mRankingMapFd = SharedMemory.create(mSharedMemoryName, mapSize);
+ if (mRankingMapFd == null) {
+ return;
+ }
+
+ // Gets a read/write buffer mapping the entire shared memory region.
+ final ByteBuffer buffer = mRankingMapFd.mapReadWrite();
+
+ // Puts the ranking map into the shared memory region buffer.
+ buffer.put(mapParcel.marshall(), 0, mapSize);
+
+ // Protects the region from being written to, by setting it to be read-only.
+ mRankingMapFd.setProtect(OsConstants.PROT_READ);
+
+ // Puts the SharedMemory object in the parcel.
+ out.writeParcelable(mRankingMapFd, flags);
+ } catch (ErrnoException e) {
+ // TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
+ // avoid crashes; change to Log.wtf.
+ throw new RuntimeException(e);
+ } finally {
+ mapParcel.recycle();
+ }
+ } else {
+ out.writeParcelable(mRankingMap, flags);
+ }
}
+ /**
+ * @hide
+ */
public static final @android.annotation.NonNull Parcelable.Creator<NotificationRankingUpdate> CREATOR
= new Parcelable.Creator<NotificationRankingUpdate>() {
public NotificationRankingUpdate createFromParcel(Parcel parcel) {
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
new file mode 100644
index 0000000..59b2bc1
--- /dev/null
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -0,0 +1,49 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsNotificationTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksUiServicesTests",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsNotificationTestCases"
+ }
+ ]
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index d87198a0..ff7d8bb 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -238,7 +238,7 @@
DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false");
DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, "true");
DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false");
- DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "true");
+ DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false");
DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true");
DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true");
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 0177904..ca3dff3 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -693,6 +693,7 @@
* @throws IllegalStateException if no frame is in progress.
* @hide
*/
+ @TestApi
@UnsupportedAppUsage
public long getFrameTimeNanos() {
synchronized (mLock) {
@@ -716,6 +717,27 @@
}
}
+ /**
+ * Gets the time in {@link System#nanoTime()} timebase which the current frame
+ * is expected to be presented.
+ * <p>
+ * This time should be used to advance any animation clocks.
+ * Prefer using this method over {@link #getFrameTimeNanos()}.
+ * </p><p>
+ * This method should only be called from within a callback.
+ * </p>
+ *
+ * @return The frame start time, in the {@link System#nanoTime()} time base.
+ *
+ * @throws IllegalStateException if no frame is in progress.
+ * @hide
+ */
+ @TestApi
+ @UnsupportedAppUsage
+ public long getExpectedPresentationTimeNanos() {
+ return mFrameData.getPreferredFrameTimeline().getExpectedPresentationTimeNanos();
+ }
+
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
@@ -869,7 +891,8 @@
Trace.traceBegin(Trace.TRACE_TAG_VIEW, message);
}
- AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
+ AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS,
+ timeline.mExpectedPresentationTimeNanos);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
@@ -1167,10 +1190,9 @@
*/
FrameTimeline update(
long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
- if (vsyncEventData.frameTimelinesLength == 0) {
- throw new IllegalArgumentException(
- "Vsync event timelines length must be greater than 0");
- }
+ // Even if the frame timelines length is 0, continue with allocation for API
+ // FrameData.getFrameTimelines consistency. The 0 length frame timelines code path
+ // should only occur when USE_VSYNC property is false.
if (mFrameTimelines.length != vsyncEventData.frameTimelinesLength) {
allocateFrameTimelines(vsyncEventData.frameTimelinesLength);
}
@@ -1207,6 +1229,10 @@
if (newPreferredDeadline < minimumDeadline) {
DisplayEventReceiver.VsyncEventData latestVsyncEventData =
displayEventReceiver.getLatestVsyncEventData();
+ if (latestVsyncEventData == null) {
+ throw new IllegalArgumentException(
+ "Could not get VsyncEventData. Did SurfaceFlinger crash?");
+ }
update(frameTimeNanos, latestVsyncEventData);
} else {
update(frameTimeNanos, newPreferredIndex);
diff --git a/core/java/android/view/ISurfaceControlViewHost.aidl b/core/java/android/view/ISurfaceControlViewHost.aidl
index 15008ae..fd4b329 100644
--- a/core/java/android/view/ISurfaceControlViewHost.aidl
+++ b/core/java/android/view/ISurfaceControlViewHost.aidl
@@ -19,6 +19,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.InsetsState;
+import android.view.ISurfaceControlViewHostParent;
import android.window.ISurfaceSyncGroup;
/**
@@ -34,4 +35,9 @@
oneway void onDispatchDetachedFromWindow();
oneway void onInsetsChanged(in InsetsState state, in Rect insetFrame);
ISurfaceSyncGroup getSurfaceSyncGroup();
+ /**
+ * Attaches the parent interface so the embedded content can communicate back to the parent.
+ * If null is passed in, it will remove the parent interface and no more updates will be sent.
+ */
+ oneway void attachParentInterface(in @nullable ISurfaceControlViewHostParent parentInterface);
}
diff --git a/core/java/android/view/ISurfaceControlViewHostParent.aidl b/core/java/android/view/ISurfaceControlViewHostParent.aidl
new file mode 100644
index 0000000..f42e001
--- /dev/null
+++ b/core/java/android/view/ISurfaceControlViewHostParent.aidl
@@ -0,0 +1,27 @@
+/*
+** Copyright 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 android.view;
+
+import android.view.WindowManager;
+
+/**
+ * API from embedded content in SurfaceControlViewHost to parent containing the embedded.
+ * {@hide}
+ */
+oneway interface ISurfaceControlViewHostParent {
+ void updateParams(in WindowManager.LayoutParams[] childAttrs);
+}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index c8cf7d9..effc127 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -54,7 +54,7 @@
private final static String TAG = "SurfaceControlViewHost";
private final ViewRootImpl mViewRoot;
private final CloseGuard mCloseGuard = CloseGuard.get();
- private WindowlessWindowManager mWm;
+ private final WindowlessWindowManager mWm;
private SurfaceControl mSurfaceControl;
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
@@ -67,9 +67,7 @@
return;
}
mViewRoot.mHandler.post(() -> {
- if (mWm != null) {
- mWm.setConfiguration(configuration);
- }
+ mWm.setConfiguration(configuration);
if (mViewRoot != null) {
mViewRoot.forceWmRelayout();
}
@@ -116,6 +114,11 @@
}
return null;
}
+
+ @Override
+ public void attachParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
+ mViewRoot.mHandler.post(() -> mWm.setParentInterface(parentInterface));
+ }
}
private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl();
@@ -148,10 +151,11 @@
private SurfaceControl mSurfaceControl;
private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
private final IBinder mInputToken;
+ @NonNull
private final ISurfaceControlViewHost mRemoteInterface;
SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection,
- IBinder inputToken, ISurfaceControlViewHost ri) {
+ IBinder inputToken, @NonNull ISurfaceControlViewHost ri) {
mSurfaceControl = sc;
mAccessibilityEmbeddedConnection = connection;
mInputToken = inputToken;
@@ -213,6 +217,7 @@
/**
* @hide
*/
+ @NonNull
public ISurfaceControlViewHost getRemoteInterface() {
return mRemoteInterface;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0e4cf89..1e268be 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
@@ -40,6 +41,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -54,6 +56,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@@ -302,6 +306,26 @@
private SurfaceControl mBlastSurfaceControl;
private BLASTBufferQueue mBlastBufferQueue;
+ private final ConcurrentLinkedQueue<WindowManager.LayoutParams> mEmbeddedWindowParams =
+ new ConcurrentLinkedQueue<>();
+
+ private final ISurfaceControlViewHostParent mSurfaceControlViewHostParent =
+ new ISurfaceControlViewHostParent.Stub() {
+ @Override
+ public void updateParams(WindowManager.LayoutParams[] childAttrs) {
+ mEmbeddedWindowParams.clear();
+ mEmbeddedWindowParams.addAll(Arrays.asList(childAttrs));
+
+ if (isAttachedToWindow()) {
+ runOnUiThread(() -> {
+ if (mParent != null) {
+ mParent.recomputeViewAttributes(SurfaceView.this);
+ }
+ });
+ }
+ }
+ };
+
public SurfaceView(Context context) {
this(context, null);
}
@@ -801,9 +825,18 @@
mBlastSurfaceControl = null;
}
- if (releaseSurfacePackage && mSurfacePackage != null) {
- mSurfacePackage.release();
- mSurfacePackage = null;
+ if (mSurfacePackage != null) {
+ try {
+ mSurfacePackage.getRemoteInterface().attachParentInterface(null);
+ mEmbeddedWindowParams.clear();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to remove parent interface from SCVH. Likely SCVH is "
+ + "already dead");
+ }
+ if (releaseSurfacePackage) {
+ mSurfacePackage.release();
+ mSurfacePackage = null;
+ }
}
applyTransactionOnVriDraw(transaction);
@@ -1854,6 +1887,12 @@
applyTransactionOnVriDraw(transaction);
}
mSurfacePackage = p;
+ try {
+ mSurfacePackage.getRemoteInterface().attachParentInterface(
+ mSurfaceControlViewHostParent);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to attach parent interface to SCVH. Likely SCVH is already dead.");
+ }
if (isFocused()) {
requestEmbeddedFocus(true);
@@ -2014,4 +2053,19 @@
mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
}
}
+
+ @Override
+ void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {
+ super.performCollectViewAttributes(attachInfo, visibility);
+ if (mEmbeddedWindowParams.isEmpty()) {
+ return;
+ }
+
+ for (WindowManager.LayoutParams embeddedWindowAttr : mEmbeddedWindowParams) {
+ if ((embeddedWindowAttr.flags & FLAG_KEEP_SCREEN_ON) == FLAG_KEEP_SCREEN_ON) {
+ attachInfo.mKeepScreenOn = true;
+ break;
+ }
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 38e3526..d0ab8a7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10411,11 +10411,6 @@
return false;
}
- // Disable triggering autofill if the view is integrated with CredentialManager.
- if (afm.shouldIgnoreCredentialViews() && isCredential()) {
- return false;
- }
-
// Check whether view is not part of an activity. If it's not, return false.
if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) {
return false;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d110ecb..f21851f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4134,6 +4134,9 @@
// implement AccessibilityNodeProvider#findFocus
AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
AccessibilityNodeProvider.HOST_VIEW_ID);
+ if (current == null) {
+ return null;
+ }
if (current.isFocused()) {
return current;
}
@@ -5459,7 +5462,7 @@
}
private void updateRenderHdrSdrRatio() {
- mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio();
+ mRenderHdrSdrRatio = Math.min(mDesiredHdrSdrRatio, mDisplay.getHdrSdrRatio());
mUpdateHdrSdrRatioInfo = true;
}
@@ -5487,22 +5490,14 @@
mHdrSdrRatioChangedListener = null;
} else {
mHdrSdrRatioChangedListener = display -> {
- setTargetHdrSdrRatio(display.getHdrSdrRatio());
+ updateRenderHdrSdrRatio();
+ invalidate();
};
mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener);
}
}
}
- /** happylint */
- public void setTargetHdrSdrRatio(float ratio) {
- if (mRenderHdrSdrRatio != ratio) {
- mRenderHdrSdrRatio = ratio;
- mUpdateHdrSdrRatioInfo = true;
- invalidate();
- }
- }
-
@Override
public void requestChildFocus(View child, View focused) {
if (DEBUG_INPUT_RESIZE) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 96bfb2d..7d3d283 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -49,7 +49,8 @@
private class State {
SurfaceControl mSurfaceControl;
- WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+ final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+ final WindowManager.LayoutParams mLastReportedParams = new WindowManager.LayoutParams();
int mDisplayId;
IBinder mInputChannelToken;
Region mInputRegion;
@@ -94,6 +95,8 @@
private final MergedConfiguration mTmpConfig = new MergedConfiguration();
private final WindowlessWindowLayout mLayout = new WindowlessWindowLayout();
+ private ISurfaceControlViewHostParent mParentInterface;
+
public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
IBinder hostInputToken) {
mRootSurface = rootSurface;
@@ -244,6 +247,7 @@
final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
WindowManagerGlobal.ADD_FLAG_USE_BLAST;
+ sendLayoutParamsToParent();
// Include whether the window is in touch mode.
return isInTouchModeInternal(displayId) ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE
: res;
@@ -425,6 +429,7 @@
outInsetsState.set(mInsetsState);
}
+ sendLayoutParamsToParent();
return 0;
}
@@ -645,4 +650,45 @@
" we shouldn't get here!");
return false;
}
+
+ void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
+ IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
+ IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
+ // If the parent interface has changed, it needs to clear the last reported params so it
+ // will update the new interface with the params.
+ if (oldInterface != newInterface) {
+ clearLastReportedParams();
+ }
+ mParentInterface = parentInterface;
+ sendLayoutParamsToParent();
+ }
+
+ private void clearLastReportedParams() {
+ WindowManager.LayoutParams emptyParam = new WindowManager.LayoutParams();
+ for (State windowInfo : mStateForWindow.values()) {
+ windowInfo.mLastReportedParams.copyFrom(emptyParam);
+ }
+ }
+
+ private void sendLayoutParamsToParent() {
+ if (mParentInterface == null) {
+ return;
+ }
+ WindowManager.LayoutParams[] params =
+ new WindowManager.LayoutParams[mStateForWindow.size()];
+ int index = 0;
+ boolean hasChanges = false;
+ for (State windowInfo : mStateForWindow.values()) {
+ int changes = windowInfo.mLastReportedParams.copyFrom(windowInfo.mParams);
+ hasChanges |= (changes != 0);
+ params[index++] = windowInfo.mParams;
+ }
+
+ if (hasChanges) {
+ try {
+ mParentInterface.updateParams(params);
+ } catch (RemoteException e) {
+ }
+ }
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index e6385a5..f3cde43 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -72,6 +72,8 @@
private final AccessibilityNodeRefresher mAccessibilityNodeRefresher;
+ private OnNodeAddedListener mOnNodeAddedListener;
+
private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
/**
@@ -542,6 +544,10 @@
mInputFocus = sourceId;
mInputFocusWindow = windowId;
}
+
+ if (mOnNodeAddedListener != null) {
+ mOnNodeAddedListener.onNodeAdded(clone);
+ }
}
}
@@ -881,6 +887,26 @@
}
}
+ /**
+ * Registers a listener to receive callbacks whenever nodes are added to cache.
+ *
+ * @param listener the listener to be registered.
+ */
+ public void registerOnNodeAddedListener(OnNodeAddedListener listener) {
+ synchronized (mLock) {
+ mOnNodeAddedListener = listener;
+ }
+ }
+
+ /**
+ * Clears the current reference to an OnNodeAddedListener, if one exists.
+ */
+ public void clearOnNodeAddedListener() {
+ synchronized (mLock) {
+ mOnNodeAddedListener = null;
+ }
+ }
+
// Layer of indirection included to break dependency chain for testing
public static class AccessibilityNodeRefresher {
/** Refresh the given AccessibilityNodeInfo object. */
@@ -893,4 +919,12 @@
return info.refresh();
}
}
+
+ /**
+ * Listener interface that receives callbacks when nodes are added to cache.
+ */
+ public interface OnNodeAddedListener {
+ /** Called when a node is added to cache. */
+ void onNodeAdded(AccessibilityNodeInfo node);
+ }
}
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 84ef226..11a80eb 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -51,6 +51,7 @@
boolean animationClockLocked;
long currentVsyncTimeMillis;
long lastReportedTimeMillis;
+ long mExpectedPresentationTimeNanos;
};
private static ThreadLocal<AnimationState> sAnimationState
@@ -62,7 +63,8 @@
};
/**
- * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current
+ * Locks AnimationUtils{@link #currentAnimationTimeMillis()} and
+ * AnimationUtils{@link #expectedPresentationTimeNanos()} to a fixed value for the current
* thread. This is used by {@link android.view.Choreographer} to ensure that all accesses
* during a vsync update are synchronized to the timestamp of the vsync.
*
@@ -74,8 +76,9 @@
* Note that time is not allowed to "rewind" and must perpetually flow forward. So the
* lock may fail if the time is in the past from a previously returned value, however
* time will be frozen for the duration of the lock. The clock is a thread-local, so
- * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and
- * {@link #currentAnimationTimeMillis()} are all called on the same thread.
+ * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()},
+ * {@link #currentAnimationTimeMillis()}, and {@link #expectedPresentationTimeNanos()}
+ * are all called on the same thread.
*
* This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()}
* will unlock the clock for everyone on the same thread. It is therefore recommended
@@ -83,12 +86,13 @@
* {@link android.view.Choreographer} instance.
*
* @hide
- * */
+ */
@TestApi
- public static void lockAnimationClock(long vsyncMillis) {
+ public static void lockAnimationClock(long vsyncMillis, long expectedPresentationTimeNanos) {
AnimationState state = sAnimationState.get();
state.animationClockLocked = true;
state.currentVsyncTimeMillis = vsyncMillis;
+ state.mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
}
/**
@@ -124,6 +128,19 @@
}
/**
+ * The expected presentation time of a frame in the {@link System#nanoTime()}.
+ * Developers should prefer using this method over {@link #currentAnimationTimeMillis()}
+ * because it offers a more accurate time for the calculating animation progress.
+ *
+ * @return the expected presentation time of a frame in the
+ * {@link System#nanoTime()} time base.
+ */
+ public static long getExpectedPresentationTimeNanos() {
+ AnimationState state = sAnimationState.get();
+ return state.mExpectedPresentationTimeNanos;
+ }
+
+ /**
* Loads an {@link Animation} object from a resource
*
* @param context Application context used to access resources
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 106a77b..956230d 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -99,7 +99,6 @@
"autofill_dialog_hints";
// START CREDENTIAL MANAGER FLAGS //
-
/**
* Indicates whether credential manager tagged views should be ignored from autofill structures.
* This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
@@ -116,22 +115,13 @@
"autofill_credential_manager_enabled";
/**
- * Indicates whether credential manager tagged views should suppress fill dialog.
+ * Indicates whether credential manager tagged views should suppress fill and save dialog.
* This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
*
* @hide
*/
- public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG =
- "autofill_credential_manager_suppress_fill_dialog";
-
- /**
- * Indicates whether credential manager tagged views should suppress save dialog.
- * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
- *
- * @hide
- */
- public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG =
- "autofill_credential_manager_suppress_save_dialog";
+ public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_AND_SAVE_DIALOG =
+ "autofill_credential_manager_suppress_fill_and_save_dialog";
// END CREDENTIAL MANAGER FLAGS //
// START AUTOFILL FOR ALL APPS FLAGS //
@@ -272,9 +262,7 @@
// CREDENTIAL MANAGER DEFAULTS
// Credential manager is enabled by default so as to allow testing by app developers
private static final boolean DEFAULT_CREDENTIAL_MANAGER_ENABLED = true;
- private static final boolean DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS = true;
- private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG = false;
- private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG = false;
+ private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_AND_SAVE_DIALOG = true;
// END CREDENTIAL MANAGER DEFAULTS
@@ -328,6 +316,7 @@
(str) -> !TextUtils.isEmpty(str));
}
+ /* starts credman flag getter function */
/**
* Whether the Credential Manager feature is enabled or not
*
@@ -341,30 +330,17 @@
}
/**
- * Whether credential manager tagged views should be ignored for autofill structure.
- *
- * @hide
- */
- public static boolean shouldIgnoreCredentialViews() {
- return isCredentialManagerEnabled()
- && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_AUTOFILL,
- DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS,
- DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS);
- }
-
- /**
* Whether credential manager tagged views should not trigger fill dialog requests.
*
* @hide
*/
- public static boolean isFillDialogDisabledForCredentialManager() {
- return isCredentialManagerEnabled()
- && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_AUTOFILL,
- DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG,
- DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG);
+ public static boolean isFillAndSaveDialogDisabledForCredentialManager() {
+ return isCredentialManagerEnabled() && DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_AND_SAVE_DIALOG,
+ DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_AND_SAVE_DIALOG);
}
+ /* ends credman flag getter function */
/**
* Whether triggering fill request on unimportant view is enabled.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 927833e..792b38b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -22,6 +22,7 @@
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_PCC_DETECTION;
import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE;
+import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
@@ -665,6 +666,8 @@
@GuardedBy("mLock")
@Nullable private Executor mRequestCallbackExecutor;
+ private boolean mScreenHasCredmanField;
+
/**
* Indicates whether there is already a field to do a fill request after
* the activity started.
@@ -680,6 +683,8 @@
private final boolean mIsFillDialogEnabled;
+ private final boolean mIsFillAndSaveDialogDisabledForCredentialManager;
+
// Indicate whether trigger fill request on unimportant views is enabled
private boolean mIsTriggerFillRequestOnUnimportantViewEnabled = false;
@@ -876,7 +881,10 @@
mIsFillDialogEnabled = AutofillFeatureFlags.isFillDialogEnabled();
mFillDialogEnabledHints = AutofillFeatureFlags.getFillDialogEnabledHints();
- mShouldIgnoreCredentialViews = AutofillFeatureFlags.shouldIgnoreCredentialViews();
+
+ mIsFillAndSaveDialogDisabledForCredentialManager =
+ AutofillFeatureFlags.isFillAndSaveDialogDisabledForCredentialManager();
+
if (sDebug) {
Log.d(TAG, "Fill dialog is enabled:" + mIsFillDialogEnabled
+ ", hints=" + Arrays.toString(mFillDialogEnabledHints));
@@ -1443,12 +1451,12 @@
if (infos.size() == 0) {
throw new IllegalArgumentException("No VirtualViewInfo found");
}
- if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
- && view.isCredential()) {
+ if (view.isCredential() && mIsFillAndSaveDialogDisabledForCredentialManager) {
if (sDebug) {
Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
+ view.getAutofillId().toString());
}
+ mScreenHasCredmanField = true;
return;
}
for (int i = 0; i < infos.size(); i++) {
@@ -1470,12 +1478,13 @@
if (sDebug) {
Log.d(TAG, "notifyViewEnteredForFillDialog:" + v.getAutofillId());
}
- if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
- && v.isCredential()) {
+ if (v.isCredential()
+ && mIsFillAndSaveDialogDisabledForCredentialManager) {
if (sDebug) {
Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
- + v.getAutofillId().toString());
+ + v.getAutofillId());
}
+ mScreenHasCredmanField = true;
return;
}
notifyViewReadyInner(v.getAutofillId(), v.getAutofillHints());
@@ -1535,7 +1544,7 @@
if (mIsFillDialogEnabled
|| ArrayUtils.containsAny(autofillHints, mFillDialogEnabledHints)) {
if (sDebug) {
- Log.d(TAG, "Trigger fill request when the view is ready.");
+ Log.d(TAG, "Triggering pre-emptive request for fill dialog.");
}
int flags = FLAG_SUPPORTS_FILL_DIALOG;
@@ -1772,6 +1781,15 @@
flags |= FLAG_PASSWORD_INPUT_TYPE;
}
+ // Update session when screen has credman field
+ if (AutofillFeatureFlags.isFillAndSaveDialogDisabledForCredentialManager()
+ && mScreenHasCredmanField) {
+ flags |= FLAG_SCREEN_HAS_CREDMAN_FIELD;
+ if (sVerbose) {
+ Log.v(TAG, "updating session with flag screen has credman view");
+ }
+ }
+
flags |= getImeStateFlag(view);
if (!isActiveLocked()) {
@@ -2072,7 +2090,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get enabled autofill services status.");
+ throw new RuntimeException("Fail to get enabled autofill services status. " + e);
}
}
@@ -2091,7 +2109,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get autofill services component name.");
+ throw new RuntimeException("Fail to get autofill services component name. " + e);
}
}
@@ -2118,7 +2136,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get user data id for field classification.");
+ throw new RuntimeException("Fail to get user data id for field classification. " + e);
}
}
@@ -2141,7 +2159,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get user data for field classification.");
+ throw new RuntimeException("Fail to get user data for field classification. " + e);
}
}
@@ -2181,7 +2199,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get field classification enabled status.");
+ throw new RuntimeException("Fail to get field classification enabled status. " + e);
}
}
@@ -2205,7 +2223,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get default field classification algorithm.");
+ throw new RuntimeException("Fail to get default field classification algorithm. " + e);
}
}
@@ -2227,7 +2245,8 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get available field classification algorithms.");
+ throw new
+ RuntimeException("Fail to get available field classification algorithms. " + e);
}
}
@@ -2251,7 +2270,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SyncResultReceiver.TimeoutException e) {
- throw new RuntimeException("Fail to get autofill supported status.");
+ throw new RuntimeException("Fail to get autofill supported status. " + e);
}
}
@@ -2523,6 +2542,7 @@
mIsFillRequested.set(false);
mShowAutofillDialogCalled = false;
mFillDialogTriggerIds = null;
+ mScreenHasCredmanField = false;
mAllTrackedViews.clear();
if (resetEnteredIds) {
mEnteredIds = null;
@@ -3636,7 +3656,8 @@
private boolean shouldShowAutofillDialog(View view, AutofillId id) {
if (!hasFillDialogUiFeature()
|| mShowAutofillDialogCalled
- || mFillDialogTriggerIds == null) {
+ || mFillDialogTriggerIds == null
+ || mScreenHasCredmanField) {
return false;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index b229106..dc3d323 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -181,8 +181,6 @@
public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9;
/** @hide */
public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10;
- /** @hide */
- public static final int FLUSH_REASON_LOGIN_DETECTED = 11;
/**
* After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps
@@ -205,8 +203,7 @@
FLUSH_REASON_SESSION_CONNECTED,
FLUSH_REASON_FORCE_FLUSH,
FLUSH_REASON_VIEW_TREE_APPEARING,
- FLUSH_REASON_VIEW_TREE_APPEARED,
- FLUSH_REASON_LOGIN_DETECTED
+ FLUSH_REASON_VIEW_TREE_APPEARED
})
@Retention(RetentionPolicy.SOURCE)
public @interface FlushReason {}
@@ -690,8 +687,6 @@
return "VIEW_TREE_APPEARING";
case FLUSH_REASON_VIEW_TREE_APPEARED:
return "VIEW_TREE_APPEARED";
- case FLUSH_REASON_LOGIN_DETECTED:
- return "LOGIN_DETECTED";
default:
return "UNKNOWN-" + reason;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index efd50e7..2241fd5 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -52,8 +52,10 @@
import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import android.view.contentprotection.ContentProtectionEventProcessor;
import android.view.inputmethod.BaseInputConnection;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import java.io.PrintWriter;
@@ -118,9 +120,13 @@
/**
* Direct interface to the service binder object - it's used to send the events, including the
* last ones (when the session is finished)
+ *
+ * @hide
*/
- @NonNull
- private IContentCaptureDirectManager mDirectServiceInterface;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @Nullable
+ public IContentCaptureDirectManager mDirectServiceInterface;
+
@Nullable
private DeathRecipient mDirectServiceVulture;
@@ -131,14 +137,19 @@
@Nullable
private IBinder mShareableActivityToken;
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@Nullable
- private ComponentName mComponentName;
+ public ComponentName mComponentName;
/**
* List of events held to be sent as a batch.
+ *
+ * @hide
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@Nullable
- private ArrayList<ContentCaptureEvent> mEvents;
+ public ArrayList<ContentCaptureEvent> mEvents;
// Used just for debugging purposes (on dump)
private long mNextFlush;
@@ -157,6 +168,11 @@
@NonNull
private final SessionStateReceiver mSessionStateReceiver;
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @Nullable
+ public ContentProtectionEventProcessor mContentProtectionEventProcessor;
+
private static class SessionStateReceiver extends IResultReceiver.Stub {
private final WeakReference<MainContentCaptureSession> mMainSession;
@@ -194,8 +210,12 @@
}
}
- protected MainContentCaptureSession(@NonNull ContentCaptureManager.StrippedContext context,
- @NonNull ContentCaptureManager manager, @NonNull Handler handler,
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public MainContentCaptureSession(
+ @NonNull ContentCaptureManager.StrippedContext context,
+ @NonNull ContentCaptureManager manager,
+ @NonNull Handler handler,
@NonNull IContentCaptureManager systemServerInterface) {
mContext = context;
mManager = manager;
@@ -273,15 +293,16 @@
}
/**
- * Callback from {@code system_server} after call to
- * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int,
- * IResultReceiver)}.
+ * Callback from {@code system_server} after call to {@link
+ * IContentCaptureManager#startSession(IBinder, ComponentName, String, int, IResultReceiver)}.
*
* @param resultCode session state
* @param binder handle to {@code IContentCaptureDirectManager}
+ * @hide
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@UiThread
- private void onSessionStarted(int resultCode, @Nullable IBinder binder) {
+ public void onSessionStarted(int resultCode, @Nullable IBinder binder) {
if (binder != null) {
mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
mDirectServiceVulture = () -> {
@@ -296,6 +317,20 @@
}
}
+ // Should not be possible for mComponentName to be null here but check anyway
+ if (mManager.mOptions.contentProtectionOptions.enableReceiver
+ && mManager.getContentProtectionEventBuffer() != null
+ && mComponentName != null) {
+ mContentProtectionEventProcessor =
+ new ContentProtectionEventProcessor(
+ mManager.getContentProtectionEventBuffer(),
+ mHandler,
+ mSystemServerInterface,
+ mComponentName.getPackageName());
+ } else {
+ mContentProtectionEventProcessor = null;
+ }
+
if ((resultCode & STATE_DISABLED) != 0) {
resetSession(resultCode);
} else {
@@ -311,8 +346,10 @@
}
}
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@UiThread
- private void sendEvent(@NonNull ContentCaptureEvent event) {
+ public void sendEvent(@NonNull ContentCaptureEvent event) {
sendEvent(event, /* forceFlush= */ false);
}
@@ -337,6 +374,25 @@
if (sVerbose) Log.v(TAG, "handleSendEvent(): ignoring when disabled");
return;
}
+
+ if (isContentProtectionReceiverEnabled()) {
+ sendContentProtectionEvent(event);
+ }
+ if (isContentCaptureReceiverEnabled()) {
+ sendContentCaptureEvent(event, forceFlush);
+ }
+ }
+
+ @UiThread
+ private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) {
+ if (mContentProtectionEventProcessor != null) {
+ mContentProtectionEventProcessor.processEvent(event);
+ }
+ }
+
+ @UiThread
+ private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+ final int eventType = event.getType();
final int maxBufferSize = mManager.mOptions.maxBufferSize;
if (mEvents == null) {
if (sVerbose) {
@@ -528,9 +584,11 @@
flush(reason);
}
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@Override
@UiThread
- void flush(@FlushReason int reason) {
+ public void flush(@FlushReason int reason) {
if (mEvents == null || mEvents.size() == 0) {
if (sVerbose) {
Log.v(TAG, "Don't flush for empty event buffer.");
@@ -544,6 +602,10 @@
return;
}
+ if (!isContentCaptureReceiverEnabled()) {
+ return;
+ }
+
if (mDirectServiceInterface == null) {
if (sVerbose) {
Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, "
@@ -607,8 +669,10 @@
return new ParceledListSlice<>(events);
}
+ /** hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@UiThread
- private void destroySession() {
+ public void destroySession() {
if (sDebug) {
Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
@@ -626,12 +690,15 @@
mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
}
mDirectServiceInterface = null;
+ mContentProtectionEventProcessor = null;
}
// TODO(b/122454205): once we support multiple sessions, we might need to move some of these
// clearings out.
+ /** @hide */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@UiThread
- private void resetSession(int newState) {
+ public void resetSession(int newState) {
if (sVerbose) {
Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
+ getStateAsString(mState) + " to " + getStateAsString(newState));
@@ -651,6 +718,7 @@
}
}
mDirectServiceInterface = null;
+ mContentProtectionEventProcessor = null;
mHandler.removeMessages(MSG_FLUSH);
}
@@ -878,4 +946,14 @@
private String getDebugState(@FlushReason int reason) {
return getDebugState() + ", reason=" + getFlushReasonAsString(reason);
}
+
+ @UiThread
+ private boolean isContentProtectionReceiverEnabled() {
+ return mManager.mOptions.contentProtectionOptions.enableReceiver;
+ }
+
+ @UiThread
+ private boolean isContentCaptureReceiverEnabled() {
+ return mManager.mOptions.enableReceiver;
+ }
}
diff --git a/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java b/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
index e49df21..b44abf3 100644
--- a/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
+++ b/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
@@ -75,6 +75,8 @@
ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED)));
+ private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;
+
@NonNull private final RingBuffer<ContentCaptureEvent> mEventBuffer;
@NonNull private final Handler mHandler;
@@ -93,6 +95,8 @@
@Nullable
public Instant mLastFlushTime;
+ private int mResetLoginRemainingEventsToProcess;
+
public ContentProtectionEventProcessor(
@NonNull RingBuffer<ContentCaptureEvent> eventBuffer,
@NonNull Handler handler,
@@ -130,6 +134,8 @@
mSuspiciousTextDetected |= isSuspiciousText(event);
if (mPasswordFieldDetected && mSuspiciousTextDetected) {
loginDetected();
+ } else {
+ maybeResetLoginFlags();
}
}
@@ -139,8 +145,28 @@
|| Instant.now().isAfter(mLastFlushTime.plus(MIN_DURATION_BETWEEN_FLUSHING))) {
flush();
}
+ resetLoginFlags();
+ }
+
+ @UiThread
+ private void resetLoginFlags() {
mPasswordFieldDetected = false;
mSuspiciousTextDetected = false;
+ mResetLoginRemainingEventsToProcess = 0;
+ }
+
+ @UiThread
+ private void maybeResetLoginFlags() {
+ if (mPasswordFieldDetected || mSuspiciousTextDetected) {
+ if (mResetLoginRemainingEventsToProcess <= 0) {
+ mResetLoginRemainingEventsToProcess = RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS;
+ } else {
+ mResetLoginRemainingEventsToProcess--;
+ if (mResetLoginRemainingEventsToProcess <= 0) {
+ resetLoginFlags();
+ }
+ }
+ }
}
@UiThread
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index 50e95c8..ee36dc7 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.util.Slog;
@@ -69,6 +70,9 @@
*/
public InputMethodSubtypeArray(final Parcel source) {
mCount = source.readInt();
+ if (mCount < 0) {
+ throw new BadParcelableException("mCount must be non-negative.");
+ }
if (mCount > 0) {
mDecompressedSize = source.readInt();
mCompressedData = source.createByteArray();
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 20230e7..0427d10 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -103,15 +103,22 @@
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
- * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
- * response header defined by
- * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
- * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
- * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
- * consult the RFC specification for a list of valid attributes.
+ * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP response
+ * header. This is a key-value pair of the form {@code "key=value"}, optionally followed by a
+ * list of cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}).
+ * For the header format and attributes supported by WebView, see the <a href=
+ * "https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie">{@code Set-Cookie}
+ * documentation on MDN</a>.
*
- * <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
- * attribute, {@code url} must use the {@code "https://"} scheme.
+ * <p class="note">
+ * <b>Notes:</b>
+ * <ul>
+ * <li>If specifying a {@code value} containing the {@code "Secure"} attribute,
+ * {@code url} must use the {@code "https://"} scheme.</li>
+ * <li>if specifying a {@code value} containing the {@code "Partitioned"}
+ * attribute, the cookie will be set for the top-level partition of the
+ * {@code url}.</li>
+ * </ul>
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
@@ -125,12 +132,12 @@
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
- * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
- * response header defined by
- * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
- * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
- * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
- * consult the RFC specification for a list of valid attributes.
+ * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP response
+ * header. This is a key-value pair of the form {@code "key=value"}, optionally followed by a
+ * list of cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}).
+ * For the header format and attributes supported by WebView, see the <a href=
+ * "https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie">{@code Set-Cookie}
+ * documentation on MDN</a>.
*
* <p>This method is asynchronous. If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue} will be called on the current
@@ -140,8 +147,15 @@
* completes or whether it succeeded, and in this case it is safe to call the method from a
* thread without a Looper.
*
- * <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
- * attribute, {@code url} must use the {@code "https://"} scheme.
+ * <p class="note">
+ * <b>Notes:</b>
+ * <ul>
+ * <li>If specifying a {@code value} containing the {@code "Secure"} attribute,
+ * {@code url} must use the {@code "https://"} scheme.</li>
+ * <li>if specifying a {@code value} containing the {@code "Partitioned"}
+ * attribute, the cookie will be set for the top-level partition of the
+ * {@code url}.</li>
+ * </ul>
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
@@ -157,6 +171,10 @@
* "; "} characters (semicolon followed by a space). Each key-value pair will be of the form
* {@code "key=value"}.
*
+ * <p class="note">
+ * <b>Note:</b> Any cookies set with the {@code "Partitioned"} attribute will only be returned
+ * for the top-level partition of {@code url}.
+ *
* @param url the URL for which the cookies are requested
* @return value the cookies as a string, using the format of the 'Cookie'
* HTTP request header
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 1d5c6f1..6f229f6 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -20,11 +20,15 @@
import android.os.Handler;
/**
- * Represents a request for handling an SSL error. Instances of this class are
- * created by the WebView and passed to
- * {@link WebViewClient#onReceivedSslError}. The host application must call
- * either {@link #proceed} or {@link #cancel} to set the WebView's response
- * to the request.
+ * Represents a request for handling an SSL error.
+ *
+ * <p>A {@link WebView} creates an instance of this class. The instance is
+ * passed to {@link WebViewClient#onReceivedSslError(WebView, SslErrorHandler,
+ * SslError)}.
+ *
+ * <p>The host application must call {@link #cancel()} or, contrary to secure
+ * web communication standards, {@link #proceed()} to provide the web view's
+ * response to the request.
*/
public class SslErrorHandler extends Handler {
@@ -35,17 +39,29 @@
public SslErrorHandler() {}
/**
- * Proceed with the SSL certificate.
- * <p>
- * It is not recommended to proceed past SSL errors and this method should
- * generally not be used; see {@link WebViewClient#onReceivedSslError} for
- * more information.
+ * Instructs the {@code WebView} that encountered the SSL certificate error
+ * to ignore the error and continue communicating with the server.
+ *
+ * <p class="warning"><b>Warning:</b> When an SSL error occurs, the host
+ * application should always call {@link #cancel()} rather than
+ * {@code proceed()} because an invalid SSL certificate means the connection
+ * is not secure.
+ *
+ * @see WebViewClient#onReceivedSslError(WebView, SslErrorHandler,
+ * SslError)
*/
public void proceed() {}
/**
- * Cancel this request and all pending requests for the WebView that had
- * the error.
+ * Instructs the {@code WebView} that encountered the SSL certificate error
+ * to terminate communication with the server. Cancels the current server
+ * request and all pending requests for the {@code WebView}.
+ *
+ * <p>The host application must call this method to prevent a resource from
+ * loading when an SSL certificate is invalid.
+ *
+ * @see WebViewClient#onReceivedSslError(WebView, SslErrorHandler,
+ * SslError)
*/
public void cancel() {}
}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 55f09f1..2dfeae3 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -382,30 +382,34 @@
}
/**
- * Notify the host application that an SSL error occurred while loading a
- * resource. The host application must call either {@link SslErrorHandler#cancel} or
- * {@link SslErrorHandler#proceed}. Note that the decision may be retained for use in
- * response to future SSL errors. The default behavior is to cancel the
- * load.
- * <p>
- * This API is only called for recoverable SSL certificate errors. In the case of
- * non-recoverable errors (such as when the server fails the client), WebView will call {@link
- * #onReceivedError(WebView, WebResourceRequest, WebResourceError)} with {@link
- * #ERROR_FAILED_SSL_HANDSHAKE}.
- * <p>
- * Applications are advised not to prompt the user about SSL errors, as
- * the user is unlikely to be able to make an informed security decision
- * and WebView does not provide any UI for showing the details of the
- * error in a meaningful way.
- * <p>
- * Application overrides of this method may display custom error pages or
- * silently log issues, but it is strongly recommended to always call
- * {@link SslErrorHandler#cancel} and never allow proceeding past errors.
+ * Notifies the host application that an SSL error occurred while loading a
+ * resource. The host application must call either
+ * {@link SslErrorHandler#cancel()} or {@link SslErrorHandler#proceed()}.
*
- * @param view The WebView that is initiating the callback.
- * @param handler An {@link SslErrorHandler} that will handle the user's
- * response.
- * @param error The SSL error object.
+ * <p class="warning"><b>Warning:</b> Application overrides of this method
+ * can be used to display custom error pages or to silently log issues, but
+ * the host application should always call {@code SslErrorHandler#cancel()}
+ * and never proceed past errors.
+ *
+ * <p class="note"><b>Note:</b> Do not prompt the user about SSL errors.
+ * Users are unlikely to be able to make an informed security decision, and
+ * {@code WebView} does not provide a UI for showing the details of the
+ * error in a meaningful way.
+ *
+ * <p>The decision to call {@code proceed()} or {@code cancel()} may be
+ * retained to facilitate responses to future SSL errors. The default
+ * behavior is to cancel the resource loading process.
+ *
+ * <p>This API is called only for recoverable SSL certificate errors. For
+ * non-recoverable errors (such as when the server fails the client), the
+ * {@code WebView} calls {@link #onReceivedError(WebView,
+ * WebResourceRequest, WebResourceError) onReceivedError(WebView,
+ * WebResourceRequest, WebResourceError)} with the
+ * {@link #ERROR_FAILED_SSL_HANDSHAKE} argument.
+ *
+ * @param view {@code WebView} that initiated the callback.
+ * @param handler {@link SslErrorHandler} that handles the user's response.
+ * @param error SSL error object.
*/
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 46f2931..a61aafa 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -8112,16 +8112,10 @@
mHighlightPaint = new Paint();
mHighlightPath = new Path();
- // The highlight color is supposed to be 12% of the color primary40. We can't
- // directly access Material 3 theme. But because Material 3 sets the colorPrimary to
- // be primary40, here we hardcoded it to be 12% of colorPrimary.
- final TypedValue typedValue = new TypedValue();
- mTextView.getContext().getTheme()
- .resolveAttribute(R.attr.colorPrimary, typedValue, true);
- final int colorPrimary = typedValue.data;
- final int highlightColor = ColorUtils.setAlphaComponent(colorPrimary,
- (int) (0.12f * Color.alpha(colorPrimary)));
- mHighlightPaint.setColor(highlightColor);
+ // Insert mode highlight color is 20% opacity of the default text color.
+ int color = mTextView.getTextColors().getDefaultColor();
+ color = ColorUtils.setAlphaComponent(color, (int) (0.2f * Color.alpha(color)));
+ mHighlightPaint.setColor(color);
}
/**
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 59238b4..d2a16a3 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -550,6 +550,16 @@
}
/**
+ * Updates the callsites of all the surfaces in this transition, which aids in the debugging of
+ * lingering surfaces.
+ */
+ public void setUnreleasedWarningCallSiteForAllSurfaces(String callsite) {
+ for (int i = mChanges.size() - 1; i >= 0; --i) {
+ mChanges.get(i).getLeash().setUnreleasedWarningCallSite(callsite);
+ }
+ }
+
+ /**
* Makes a copy of this as if it were parcel'd and unparcel'd. This implies that surfacecontrol
* refcounts are incremented which allows the "remote" receiver to release them without breaking
* the caller's references. Use this only if you need to "send" this to a local function which
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 57cc38c..0ea8014 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -59,6 +59,8 @@
public static final int INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS = 6;
/** value for INVOCATION_TYPE_KEY: press on physcial assistant button */
public static final int INVOCATION_TYPE_ASSIST_BUTTON = 7;
+ /** value for INVOCATION_TYPE_KEY: long press on nav handle */
+ public static final int INVOCATION_TYPE_NAV_HANDLE_LONG_PRESS = 8;
private final Context mContext;
private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index bf26568..4e7bfe5 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -16,42 +16,50 @@
package com.android.internal.app;
-import static android.graphics.PixelFormat.TRANSLUCENT;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
import android.animation.ObjectAnimator;
+import android.animation.TimeAnimator;
+import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.CombinedVibration;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.VibrationEffect;
+import android.os.VibratorManager;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.AnalogClock;
+import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.R;
import org.json.JSONObject;
-import java.time.Clock;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
+import java.util.Random;
/**
* @hide
@@ -59,30 +67,160 @@
public class PlatLogoActivity extends Activity {
private static final String TAG = "PlatLogoActivity";
- private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
+ private static final long LAUNCH_TIME = 5000L;
- private SettableAnalogClock mClock;
+ private static final String U_EGG_UNLOCK_SETTING = "egg_mode_u";
+
+ private static final float MIN_WARP = 1f;
+ private static final float MAX_WARP = 10f; // after all these years
+ private static final boolean FINISH_AFTER_NEXT_STAGE_LAUNCH = false;
+
private ImageView mLogo;
- private BubblesDrawable mBg;
+ private Starfield mStarfield;
+
+ private FrameLayout mLayout;
+
+ private TimeAnimator mAnim;
+ private ObjectAnimator mWarpAnim;
+ private Random mRandom;
+ private float mDp;
+
+ private RumblePack mRumble;
+
+ private boolean mAnimationsEnabled = true;
+
+ private final View.OnTouchListener mTouchListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ measureTouchPressure(event);
+ startWarp();
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ stopWarp();
+ break;
+ }
+ return true;
+ }
+
+ };
+
+ private final Runnable mLaunchNextStage = () -> {
+ stopWarp();
+ launchNextStage(false);
+ };
+
+ private final TimeAnimator.TimeListener mTimeListener = new TimeAnimator.TimeListener() {
+ @Override
+ public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+ mStarfield.update(deltaTime);
+ final float warpFrac = (mStarfield.getWarp() - MIN_WARP) / (MAX_WARP - MIN_WARP);
+ if (mAnimationsEnabled) {
+ mLogo.setTranslationX(mRandom.nextFloat() * warpFrac * 5 * mDp);
+ mLogo.setTranslationY(mRandom.nextFloat() * warpFrac * 5 * mDp);
+ }
+ if (warpFrac > 0f) {
+ mRumble.rumble(warpFrac);
+ }
+ mLayout.postInvalidate();
+ }
+ };
+
+ private class RumblePack implements Handler.Callback {
+ private static final int MSG = 6464;
+ private static final int INTERVAL = 50;
+
+ private final VibratorManager mVibeMan;
+ private final HandlerThread mVibeThread;
+ private final Handler mVibeHandler;
+ private boolean mSpinPrimitiveSupported;
+
+ private long mLastVibe = 0;
+
+ @SuppressLint("MissingPermission")
+ @Override
+ public boolean handleMessage(Message msg) {
+ final float warpFrac = msg.arg1 / 100f;
+ if (mSpinPrimitiveSupported) {
+ if (msg.getWhen() > mLastVibe + INTERVAL) {
+ mLastVibe = msg.getWhen();
+ mVibeMan.vibrate(CombinedVibration.createParallel(
+ VibrationEffect.startComposition()
+ .addPrimitive(PRIMITIVE_SPIN, (float) Math.pow(warpFrac, 3.0))
+ .compose()
+ ));
+ }
+ } else {
+ if (mRandom.nextFloat() < warpFrac) {
+ mLogo.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ }
+ }
+ return false;
+ }
+ RumblePack() {
+ mVibeMan = getSystemService(VibratorManager.class);
+ mSpinPrimitiveSupported = mVibeMan.getDefaultVibrator()
+ .areAllPrimitivesSupported(PRIMITIVE_SPIN);
+
+ mVibeThread = new HandlerThread("VibratorThread");
+ mVibeThread.start();
+ mVibeHandler = Handler.createAsync(mVibeThread.getLooper(), this);
+ }
+
+ public void destroy() {
+ mVibeThread.quit();
+ }
+
+ private void rumble(float warpFrac) {
+ if (!mVibeThread.isAlive()) return;
+
+ final Message msg = Message.obtain();
+ msg.what = MSG;
+ msg.arg1 = (int) (warpFrac * 100);
+ mVibeHandler.removeMessages(MSG);
+ mVibeHandler.sendMessage(msg);
+ }
+
+ }
@Override
- protected void onPause() {
- super.onPause();
+ protected void onDestroy() {
+ mRumble.destroy();
+
+ super.onDestroy();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().setDecorFitsSystemWindows(false);
getWindow().setNavigationBarColor(0);
getWindow().setStatusBarColor(0);
+ getWindow().getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
final ActionBar ab = getActionBar();
if (ab != null) ab.hide();
- final FrameLayout layout = new FrameLayout(this);
+ try {
+ mAnimationsEnabled = Settings.Global.getFloat(getContentResolver(),
+ Settings.Global.ANIMATOR_DURATION_SCALE) > 0f;
+ } catch (Settings.SettingNotFoundException e) {
+ mAnimationsEnabled = true;
+ }
- mClock = new SettableAnalogClock(this);
+ mRumble = new RumblePack();
+
+ mLayout = new FrameLayout(this);
+ mRandom = new Random();
+ mDp = getResources().getDisplayMetrics().density;
+ mStarfield = new Starfield(mRandom, mDp * 2f);
+ mStarfield.setVelocity(
+ 200f * (mRandom.nextFloat() - 0.5f),
+ 200f * (mRandom.nextFloat() - 0.5f));
+ mLayout.setBackground(mStarfield);
final DisplayMetrics dm = getResources().getDisplayMetrics();
final float dp = dm.density;
@@ -90,22 +228,79 @@
final int widgetSize = (int) (minSide * 0.75);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(widgetSize, widgetSize);
lp.gravity = Gravity.CENTER;
- layout.addView(mClock, lp);
mLogo = new ImageView(this);
- mLogo.setVisibility(View.GONE);
mLogo.setImageResource(R.drawable.platlogo);
- layout.addView(mLogo, lp);
+ mLogo.setOnTouchListener(mTouchListener);
+ mLogo.requestFocus();
+ mLayout.addView(mLogo, lp);
- mBg = new BubblesDrawable();
- mBg.setLevel(0);
- mBg.avoid = widgetSize / 2;
- mBg.padding = 0.5f * dp;
- mBg.minR = 1 * dp;
- layout.setBackground(mBg);
- layout.setOnLongClickListener(mBg);
+ Log.v(TAG, "Hello");
- setContentView(layout);
+ setContentView(mLayout);
+ }
+
+ private void startAnimating() {
+ mAnim = new TimeAnimator();
+ mAnim.setTimeListener(mTimeListener);
+ mAnim.start();
+ }
+
+ private void stopAnimating() {
+ mAnim.cancel();
+ mAnim = null;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_SPACE) {
+ if (event.getRepeatCount() == 0) {
+ startWarp();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_SPACE) {
+ stopWarp();
+ return true;
+ }
+ return false;
+ }
+
+ private void startWarp() {
+ stopWarp();
+ mWarpAnim = ObjectAnimator.ofFloat(mStarfield, "warp", MIN_WARP, MAX_WARP)
+ .setDuration(LAUNCH_TIME);
+ mWarpAnim.start();
+
+ mLogo.postDelayed(mLaunchNextStage, LAUNCH_TIME + 1000L);
+ }
+
+ private void stopWarp() {
+ if (mWarpAnim != null) {
+ mWarpAnim.cancel();
+ mWarpAnim.removeAllListeners();
+ mWarpAnim = null;
+ }
+ mStarfield.setWarp(1f);
+ mLogo.removeCallbacks(mLaunchNextStage);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startAnimating();
+ }
+
+ @Override
+ public void onPause() {
+ stopWarp();
+ stopAnimating();
+ super.onPause();
}
private boolean shouldWriteSettings() {
@@ -113,38 +308,14 @@
}
private void launchNextStage(boolean locked) {
- mClock.animate()
- .alpha(0f).scaleX(0.5f).scaleY(0.5f)
- .withEndAction(() -> mClock.setVisibility(View.GONE))
- .start();
-
- mLogo.setAlpha(0f);
- mLogo.setScaleX(0.5f);
- mLogo.setScaleY(0.5f);
- mLogo.setVisibility(View.VISIBLE);
- mLogo.animate()
- .alpha(1f)
- .scaleX(1f)
- .scaleY(1f)
- .setInterpolator(new OvershootInterpolator())
- .start();
-
- mLogo.postDelayed(() -> {
- final ObjectAnimator anim = ObjectAnimator.ofInt(mBg, "level", 0, 10000);
- anim.setInterpolator(new DecelerateInterpolator(1f));
- anim.start();
- },
- 500
- );
-
final ContentResolver cr = getContentResolver();
try {
if (shouldWriteSettings()) {
- Log.v(TAG, "Saving egg unlock=" + locked);
+ Log.v(TAG, "Saving egg locked=" + locked);
syncTouchPressure();
Settings.System.putLong(cr,
- S_EGG_UNLOCK_SETTING,
+ U_EGG_UNLOCK_SETTING,
locked ? 0 : System.currentTimeMillis());
}
} catch (RuntimeException e) {
@@ -152,14 +323,18 @@
}
try {
- startActivity(new Intent(Intent.ACTION_MAIN)
+ final Intent eggActivity = new Intent(Intent.ACTION_MAIN)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK)
- .addCategory("com.android.internal.category.PLATLOGO"));
+ .addCategory("com.android.internal.category.PLATLOGO");
+ Log.v(TAG, "launching: " + eggActivity);
+ startActivity(eggActivity);
} catch (ActivityNotFoundException ex) {
Log.e("com.android.internal.app.PlatLogoActivity", "No more eggs.");
}
- //finish(); // no longer finish upon unlock; it's fun to frob the dial
+ if (FINISH_AFTER_NEXT_STAGE_LAUNCH) {
+ finish(); // we're done here.
+ }
}
static final String TOUCH_STATS = "touch.stats";
@@ -217,266 +392,111 @@
super.onStop();
}
- /**
- * Subclass of AnalogClock that allows the user to flip up the glass and adjust the hands.
- */
- public class SettableAnalogClock extends AnalogClock {
- private int mOverrideHour = -1;
- private int mOverrideMinute = -1;
- private boolean mOverride = false;
+ private static class Starfield extends Drawable {
+ private static final int NUM_STARS = 34; // Build.VERSION_CODES.UPSIDE_DOWN_CAKE
- public SettableAnalogClock(Context context) {
- super(context);
+ private static final int NUM_PLANES = 2;
+ private final float[] mStars = new float[NUM_STARS * 4];
+ private float mVx, mVy;
+ private long mDt = 0;
+ private final Paint mStarPaint;
+
+ private final Random mRng;
+ private final float mSize;
+
+ private final Rect mSpace = new Rect();
+ private float mWarp = 1f;
+
+ private float mBuffer;
+
+ public void setWarp(float warp) {
+ mWarp = warp;
+ }
+
+ public float getWarp() {
+ return mWarp;
+ }
+
+ Starfield(Random rng, float size) {
+ mRng = rng;
+ mSize = size;
+ mStarPaint = new Paint();
+ mStarPaint.setStyle(Paint.Style.STROKE);
+ mStarPaint.setColor(Color.WHITE);
}
@Override
- protected Instant now() {
- final Instant realNow = super.now();
- final ZoneId tz = Clock.systemDefaultZone().getZone();
- final ZonedDateTime zdTime = realNow.atZone(tz);
- if (mOverride) {
- if (mOverrideHour < 0) {
- mOverrideHour = zdTime.getHour();
- }
- return Clock.fixed(zdTime
- .withHour(mOverrideHour)
- .withMinute(mOverrideMinute)
- .withSecond(0)
- .toInstant(), tz).instant();
- } else {
- return realNow;
+ public void onBoundsChange(Rect bounds) {
+ mSpace.set(bounds);
+ mBuffer = mSize * NUM_PLANES * 2 * MAX_WARP;
+ mSpace.inset(-(int) mBuffer, -(int) mBuffer);
+ final float w = mSpace.width();
+ final float h = mSpace.height();
+ for (int i = 0; i < NUM_STARS; i++) {
+ mStars[4 * i] = mRng.nextFloat() * w;
+ mStars[4 * i + 1] = mRng.nextFloat() * h;
+ mStars[4 * i + 2] = mStars[4 * i];
+ mStars[4 * i + 3] = mStars[4 * i + 1];
}
}
- double toPositiveDegrees(double rad) {
- return (Math.toDegrees(rad) + 360 - 90) % 360;
+ public void setVelocity(float x, float y) {
+ mVx = x;
+ mVy = y;
}
@Override
- public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mOverride = true;
- // pass through
- case MotionEvent.ACTION_MOVE:
- measureTouchPressure(ev);
+ public void draw(@NonNull Canvas canvas) {
+ final float dtSec = mDt / 1000f;
+ final float dx = (mVx * dtSec * mWarp);
+ final float dy = (mVy * dtSec * mWarp);
- float x = ev.getX();
- float y = ev.getY();
- float cx = getWidth() / 2f;
- float cy = getHeight() / 2f;
- float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy));
+ final boolean inWarp = mWarp > 1f;
- int minutes = (75 - (int) (angle / 6)) % 60;
- int minuteDelta = minutes - mOverrideMinute;
- if (minuteDelta != 0) {
- if (Math.abs(minuteDelta) > 45 && mOverrideHour >= 0) {
- int hourDelta = (minuteDelta < 0) ? 1 : -1;
- mOverrideHour = (mOverrideHour + 24 + hourDelta) % 24;
- }
- mOverrideMinute = minutes;
- if (mOverrideMinute == 0) {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- if (getScaleX() == 1f) {
- setScaleX(1.05f);
- setScaleY(1.05f);
- animate().scaleX(1f).scaleY(1f).setDuration(150).start();
- }
- } else {
- performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
- }
+ canvas.drawColor(Color.BLACK); // 0xFF16161D);
- onTimeChanged();
- postInvalidate();
- }
-
- return true;
- case MotionEvent.ACTION_UP:
- if (mOverrideMinute == 0 && (mOverrideHour % 12) == 1) {
- Log.v(TAG, "13:00");
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- launchNextStage(false);
- }
- return true;
- }
- return false;
- }
- }
-
- private static final String[][] EMOJI_SETS = {
- {"🍇", "🍈", "🍉", "🍊", "🍋", "🍌", "🍍", "🥭", "🍎", "🍏", "🍐", "🍑",
- "🍒", "🍓", "🫐", "🥝"},
- {"😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"},
- {"😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃", "🫠", "😉", "😊",
- "😇", "🥰", "😍", "🤩", "😘", "😗", "☺️", "😚", "😙", "🥲", "😋", "😛", "😜",
- "🤪", "😝", "🤑", "🤗", "🤭", "🫢", "🫣", "🤫", "🤔", "🫡", "🤐", "🤨", "😐",
- "😑", "😶", "🫥", "😏", "😒", "🙄", "😬", "🤥", "😌", "😔", "😪", "🤤", "😴",
- "😷"},
- { "🤩", "😍", "🥰", "😘", "🥳", "🥲", "🥹" },
- { "🫠" },
- {"💘", "💝", "💖", "💗", "💓", "💞", "💕", "❣", "💔", "❤", "🧡", "💛",
- "💚", "💙", "💜", "🤎", "🖤", "🤍"},
- // {"👁", "️🫦", "👁️"}, // this one is too much
- {"👽", "🛸", "✨", "🌟", "💫", "🚀", "🪐", "🌙", "⭐", "🌍"},
- {"🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"},
- {"🐙", "🪸", "🦑", "🦀", "🦐", "🐡", "🦞", "🐠", "🐟", "🐳", "🐋", "🐬", "🫧", "🌊",
- "🦈"},
- {"🙈", "🙉", "🙊", "🐵", "🐒"},
- {"♈", "♉", "♊", "♋", "♌", "♍", "♎", "♏", "♐", "♑", "♒", "♓"},
- {"🕛", "🕧", "🕐", "🕜", "🕑", "🕝", "🕒", "🕞", "🕓", "🕟", "🕔", "🕠", "🕕", "🕡",
- "🕖", "🕢", "🕗", "🕣", "🕘", "🕤", "🕙", "🕥", "🕚", "🕦"},
- {"🌺", "🌸", "💮", "🏵️", "🌼", "🌿"},
- {"🐢", "✨", "🌟", "👑"}
- };
-
- static class Bubble {
- public float x, y, r;
- public int color;
- public String text = null;
- }
-
- class BubblesDrawable extends Drawable implements View.OnLongClickListener {
- private static final int MAX_BUBBS = 2000;
-
- private final int[] mColorIds = {
- android.R.color.system_accent3_400,
- android.R.color.system_accent3_500,
- android.R.color.system_accent3_600,
-
- android.R.color.system_accent2_400,
- android.R.color.system_accent2_500,
- android.R.color.system_accent2_600,
- };
-
- private int[] mColors = new int[mColorIds.length];
-
- private int mEmojiSet = -1;
-
- private final Bubble[] mBubbs = new Bubble[MAX_BUBBS];
- private int mNumBubbs;
-
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- public float avoid = 0f;
- public float padding = 0f;
- public float minR = 0f;
-
- BubblesDrawable() {
- for (int i = 0; i < mColorIds.length; i++) {
- mColors[i] = getColor(mColorIds[i]);
- }
- for (int j = 0; j < mBubbs.length; j++) {
- mBubbs[j] = new Bubble();
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (getLevel() == 0) return;
- final float f = getLevel() / 10000f;
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setTextAlign(Paint.Align.CENTER);
- int drawn = 0;
- for (int j = 0; j < mNumBubbs; j++) {
- if (mBubbs[j].color == 0 || mBubbs[j].r == 0) continue;
- if (mBubbs[j].text != null) {
- mPaint.setTextSize(mBubbs[j].r * 1.75f);
- canvas.drawText(mBubbs[j].text, mBubbs[j].x,
- mBubbs[j].y + mBubbs[j].r * f * 0.6f, mPaint);
- } else {
- mPaint.setColor(mBubbs[j].color);
- canvas.drawCircle(mBubbs[j].x, mBubbs[j].y, mBubbs[j].r * f, mPaint);
- }
- drawn++;
- }
- }
-
- public void chooseEmojiSet() {
- mEmojiSet = (int) (Math.random() * EMOJI_SETS.length);
- final String[] emojiSet = EMOJI_SETS[mEmojiSet];
- for (int j = 0; j < mBubbs.length; j++) {
- mBubbs[j].text = emojiSet[(int) (Math.random() * emojiSet.length)];
- }
- invalidateSelf();
- }
-
- @Override
- protected boolean onLevelChange(int level) {
- invalidateSelf();
- return true;
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- super.onBoundsChange(bounds);
- randomize();
- }
-
- private void randomize() {
- final float w = getBounds().width();
- final float h = getBounds().height();
- final float maxR = Math.min(w, h) / 3f;
- mNumBubbs = 0;
- if (avoid > 0f) {
- mBubbs[mNumBubbs].x = w / 2f;
- mBubbs[mNumBubbs].y = h / 2f;
- mBubbs[mNumBubbs].r = avoid;
- mBubbs[mNumBubbs].color = 0;
- mNumBubbs++;
- }
- for (int j = 0; j < MAX_BUBBS; j++) {
- // a simple but time-tested bubble-packing algorithm:
- // 1. pick a spot
- // 2. shrink the bubble until it is no longer overlapping any other bubble
- // 3. if the bubble hasn't popped, keep it
- int tries = 5;
- while (tries-- > 0) {
- float x = (float) Math.random() * w;
- float y = (float) Math.random() * h;
- float r = Math.min(Math.min(x, w - x), Math.min(y, h - y));
-
- // shrink radius to fit other bubbs
- for (int i = 0; i < mNumBubbs; i++) {
- r = (float) Math.min(r,
- Math.hypot(x - mBubbs[i].x, y - mBubbs[i].y) - mBubbs[i].r
- - padding);
- if (r < minR) break;
- }
-
- if (r >= minR) {
- // we have found a spot for this bubble to live, let's save it and move on
- r = Math.min(maxR, r);
-
- mBubbs[mNumBubbs].x = x;
- mBubbs[mNumBubbs].y = y;
- mBubbs[mNumBubbs].r = r;
- mBubbs[mNumBubbs].color = mColors[(int) (Math.random() * mColors.length)];
- mNumBubbs++;
- break;
- }
+ if (mDt > 0 && mDt < 1000) {
+ canvas.translate(
+ -(mBuffer) + mRng.nextFloat() * (mWarp - 1f),
+ -(mBuffer) + mRng.nextFloat() * (mWarp - 1f)
+ );
+ final float w = mSpace.width();
+ final float h = mSpace.height();
+ for (int i = 0; i < NUM_STARS; i++) {
+ final int plane = (int) ((((float) i) / NUM_STARS) * NUM_PLANES) + 1;
+ mStars[4 * i + 2] = (mStars[4 * i + 2] + dx * plane + w) % w;
+ mStars[4 * i + 3] = (mStars[4 * i + 3] + dy * plane + h) % h;
+ mStars[4 * i + 0] = inWarp ? mStars[4 * i + 2] - dx * mWarp * 2 * plane : -100;
+ mStars[4 * i + 1] = inWarp ? mStars[4 * i + 3] - dy * mWarp * 2 * plane : -100;
}
}
- Log.v(TAG, String.format("successfully placed %d bubbles (%d%%)",
- mNumBubbs, (int) (100f * mNumBubbs / MAX_BUBBS)));
+ final int slice = (mStars.length / NUM_PLANES / 4) * 4;
+ for (int p = 0; p < NUM_PLANES; p++) {
+ mStarPaint.setStrokeWidth(mSize * (p + 1));
+ if (inWarp) {
+ canvas.drawLines(mStars, p * slice, slice, mStarPaint);
+ }
+ canvas.drawPoints(mStars, p * slice, slice, mStarPaint);
+ }
}
@Override
- public void setAlpha(int alpha) { }
+ public void setAlpha(int alpha) {
+
+ }
@Override
- public void setColorFilter(ColorFilter colorFilter) { }
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+
+ }
@Override
public int getOpacity() {
- return TRANSLUCENT;
+ return PixelFormat.OPAQUE;
}
- @Override
- public boolean onLongClick(View v) {
- if (getLevel() == 0) return false;
- chooseEmojiSet();
- return true;
+ public void update(long dt) {
+ mDt = dt;
}
}
-
-}
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 4cb592e..9ffccb3 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -118,6 +118,9 @@
*/
public static final String NAS_DEFAULT_SERVICE = "nas_default_service";
+ /** (boolean) Whether notify() calls to NMS should acquire and hold WakeLocks. */
+ public static final String NOTIFY_WAKELOCK = "nms_notify_wakelock";
+
// Flags related to media notifications
/**
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 3d95dd3..6b8ae94 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -81,6 +81,14 @@
/** Gating the logging of DND state change events. */
public static final Flag LOG_DND_STATE_EVENTS =
releasedFlag("persist.sysui.notification.log_dnd_state_events");
+
+ /** Gating the holding of WakeLocks until NLSes are told about a new notification. */
+ public static final Flag WAKE_LOCK_FOR_POSTING_NOTIFICATION =
+ devFlag("persist.sysui.notification.wake_lock_for_posting_notification");
+
+ /** Gating storing NotificationRankingUpdate ranking map in shared memory. */
+ public static final Flag RANKING_UPDATE_ASHMEM = devFlag(
+ "persist.sysui.notification.ranking_update_ashmem");
}
//// == End of flags. Everything below this line is the implementation. == ////
diff --git a/core/java/com/android/internal/content/OWNERS b/core/java/com/android/internal/content/OWNERS
index c42bee6..c8e4005 100644
--- a/core/java/com/android/internal/content/OWNERS
+++ b/core/java/com/android/internal/content/OWNERS
@@ -1,5 +1,7 @@
# Bug component: 36137
include /core/java/android/content/pm/OWNERS
+per-file FileSystemProvider.java = file:/core/java/android/os/storage/OWNERS
+
per-file ReferrerIntent.aidl = file:/services/core/java/com/android/server/am/OWNERS
per-file ReferrerIntent.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
index 80d753c..f62ff38 100644
--- a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
+++ b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
@@ -24,6 +24,7 @@
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__EXECUTING_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__INPUT_DISPATCHING_TIMEOUT;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__INPUT_DISPATCHING_TIMEOUT_NO_FOCUSED_WINDOW;
+import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__JOB_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__SHORT_FGS_TIMEOUT;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__START_FOREGROUND_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__UNKNOWN_ANR_TYPE;
@@ -545,6 +546,8 @@
return ANRLATENCY_REPORTED__ANR_TYPE__CONTENT_PROVIDER_NOT_RESPONDING;
case TimeoutKind.SHORT_FGS_TIMEOUT:
return ANRLATENCY_REPORTED__ANR_TYPE__SHORT_FGS_TIMEOUT;
+ case TimeoutKind.JOB_SERVICE:
+ return ANRLATENCY_REPORTED__ANR_TYPE__JOB_SERVICE;
default:
return ANRLATENCY_REPORTED__ANR_TYPE__UNKNOWN_ANR_TYPE;
}
diff --git a/core/java/com/android/internal/util/TraceBuffer.java b/core/java/com/android/internal/util/TraceBuffer.java
index fcc77bd4..c23e902 100644
--- a/core/java/com/android/internal/util/TraceBuffer.java
+++ b/core/java/com/android/internal/util/TraceBuffer.java
@@ -18,6 +18,7 @@
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
@@ -39,12 +40,13 @@
* {@hide}
*/
public class TraceBuffer<P, S extends P, T extends P> {
- private final Object mBufferLock = new Object();
-
private final ProtoProvider<P, S, T> mProtoProvider;
+ @GuardedBy("this")
private final Queue<T> mBuffer = new ArrayDeque<>();
private final Consumer mProtoDequeuedCallback;
+ @GuardedBy("this")
private int mBufferUsedSize;
+ @GuardedBy("this")
private int mBufferCapacity;
/**
@@ -115,18 +117,18 @@
resetBuffer();
}
- public int getAvailableSpace() {
+ public synchronized int getAvailableSpace() {
return mBufferCapacity - mBufferUsedSize;
}
/**
* Returns buffer size.
*/
- public int size() {
+ public synchronized int size() {
return mBuffer.size();
}
- public void setCapacity(int capacity) {
+ public synchronized void setCapacity(int capacity) {
mBufferCapacity = capacity;
}
@@ -137,22 +139,19 @@
* @throws IllegalStateException if the element cannot be added because it is larger
* than the buffer size.
*/
- public void add(T proto) {
+ public synchronized void add(T proto) {
int protoLength = mProtoProvider.getItemSize(proto);
if (protoLength > mBufferCapacity) {
throw new IllegalStateException("Trace object too large for the buffer. Buffer size:"
+ mBufferCapacity + " Object size: " + protoLength);
}
- synchronized (mBufferLock) {
- discardOldest(protoLength);
- mBuffer.add(proto);
- mBufferUsedSize += protoLength;
- mBufferLock.notify();
- }
+ discardOldest(protoLength);
+ mBuffer.add(proto);
+ mBufferUsedSize += protoLength;
}
@VisibleForTesting
- public boolean contains(byte[] other) {
+ public synchronized boolean contains(byte[] other) {
return mBuffer.stream()
.anyMatch(p -> Arrays.equals(mProtoProvider.getBytes(p), other));
}
@@ -160,15 +159,13 @@
/**
* Writes the trace buffer to disk inside the encapsulatingProto.
*/
- public void writeTraceToFile(File traceFile, S encapsulatingProto)
+ public synchronized void writeTraceToFile(File traceFile, S encapsulatingProto)
throws IOException {
- synchronized (mBufferLock) {
- traceFile.delete();
- try (OutputStream os = new FileOutputStream(traceFile)) {
- traceFile.setReadable(true /* readable */, false /* ownerOnly */);
- mProtoProvider.write(encapsulatingProto, mBuffer, os);
- os.flush();
- }
+ traceFile.delete();
+ try (OutputStream os = new FileOutputStream(traceFile)) {
+ traceFile.setReadable(true /* readable */, false /* ownerOnly */);
+ mProtoProvider.write(encapsulatingProto, mBuffer, os);
+ os.flush();
}
}
@@ -199,31 +196,27 @@
/**
* Removes all elements from the buffer
*/
- public void resetBuffer() {
- synchronized (mBufferLock) {
- if (mProtoDequeuedCallback != null) {
- for (T item : mBuffer) {
- mProtoDequeuedCallback.accept(item);
- }
+ public synchronized void resetBuffer() {
+ if (mProtoDequeuedCallback != null) {
+ for (T item : mBuffer) {
+ mProtoDequeuedCallback.accept(item);
}
- mBuffer.clear();
- mBufferUsedSize = 0;
}
+ mBuffer.clear();
+ mBufferUsedSize = 0;
}
@VisibleForTesting
- public int getBufferSize() {
+ public synchronized int getBufferSize() {
return mBufferUsedSize;
}
/**
* Returns the buffer status in human-readable form.
*/
- public String getStatus() {
- synchronized (mBufferLock) {
- return "Buffer size: " + mBufferCapacity + " bytes" + "\n"
- + "Buffer usage: " + mBufferUsedSize + " bytes" + "\n"
- + "Elements in the buffer: " + mBuffer.size();
- }
+ public synchronized String getStatus() {
+ return "Buffer size: " + mBufferCapacity + " bytes" + "\n"
+ + "Buffer usage: " + mBufferUsedSize + " bytes" + "\n"
+ + "Elements in the buffer: " + mBuffer.size();
}
}
diff --git a/core/java/com/android/internal/widget/FadingWearableScrollView.java b/core/java/com/android/internal/widget/FadingWearableScrollView.java
new file mode 100644
index 0000000..050952c
--- /dev/null
+++ b/core/java/com/android/internal/widget/FadingWearableScrollView.java
@@ -0,0 +1,86 @@
+/*
+ * 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.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/** ScrollView that includes scaling and fading animations */
+public class FadingWearableScrollView extends ScrollView {
+ private ViewGroupFader mFader;
+
+ public FadingWearableScrollView(Context context) {
+ this(context, null);
+ }
+
+ public FadingWearableScrollView(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.scrollViewStyle);
+ }
+
+ public FadingWearableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public FadingWearableScrollView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ mFader = createFader(this);
+ }
+
+ /**
+ * Creates a simple ViewGroupFader that animates views from both top and bottom.
+ */
+ private ViewGroupFader createFader(ViewGroup container) {
+ return new ViewGroupFader(
+ container,
+ new ViewGroupFader.AnimationCallback() {
+ @Override
+ public boolean shouldFadeFromTop(View view) {
+ return true;
+ }
+
+ @Override
+ public boolean shouldFadeFromBottom(View view) {
+ return true;
+ }
+
+ @Override
+ public void viewHasBecomeFullSize(View view) {
+ }
+ },
+ new ViewGroupFader.GlobalVisibleViewBoundsProvider());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ mFader.updateFade();
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ mFader.updateFade();
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ddd58bc..12fd6c5 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -47,6 +47,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -160,9 +161,17 @@
*/
public static final int VERIFY_FLAG_REQUEST_GK_PW_HANDLE = 1 << 0;
+ /**
+ * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the
+ * method writes the password data to the repair mode file after the credential is verified
+ * successfully.
+ */
+ public static final int VERIFY_FLAG_WRITE_REPAIR_MODE_PW = 1 << 1;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
- VERIFY_FLAG_REQUEST_GK_PW_HANDLE
+ VERIFY_FLAG_REQUEST_GK_PW_HANDLE,
+ VERIFY_FLAG_WRITE_REPAIR_MODE_PW
})
public @interface VerifyFlag {}
@@ -171,6 +180,11 @@
*/
public static final int USER_FRP = UserHandle.USER_NULL + 1;
+ /**
+ * Special user id for triggering the exiting repair mode verification flow.
+ */
+ public static final int USER_REPAIR_MODE = UserHandle.USER_NULL + 2;
+
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
@@ -200,6 +214,8 @@
public static final String CURRENT_LSKF_BASED_PROTECTOR_ID_KEY = "sp-handle";
public static final String PASSWORD_HISTORY_DELIMITER = ",";
+ private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
+
/**
* drives the pin auto confirmation feature availability in code logic.
*/
@@ -388,7 +404,7 @@
@UnsupportedAppUsage
public void reportFailedPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
@@ -397,7 +413,7 @@
@UnsupportedAppUsage
public void reportSuccessfulPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
@@ -405,21 +421,21 @@
}
public void reportPasswordLockout(int timeoutMs, int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getTrustManager().reportUnlockLockout(timeoutMs, userId);
}
public int getCurrentFailedPasswordAttempts(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return 0;
}
return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
}
public int getMaximumFailedPasswordsForWipe(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return 0;
}
return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
@@ -739,6 +755,17 @@
}
}
+ /** Returns the credential type corresponding to the given PIN or password quality. */
+ public static int pinOrPasswordQualityToCredentialType(int quality) {
+ if (isQualityAlphabeticPassword(quality)) {
+ return CREDENTIAL_TYPE_PASSWORD;
+ }
+ if (isQualityNumericPin(quality)) {
+ return CREDENTIAL_TYPE_PIN;
+ }
+ throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
+ }
+
/**
* Save a new lockscreen credential.
*
@@ -973,7 +1000,7 @@
}
@Override
public boolean shouldBypassCache(Integer userHandle) {
- return userHandle == USER_FRP;
+ return isSpecialUserId(userHandle);
}
};
@@ -1080,9 +1107,10 @@
@UnsupportedAppUsage
public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
- if (userId == USER_FRP) {
- // For secure password storage (that is required for FRP), the underlying storage also
- // enforces the deadline. Since we cannot store settings for the FRP user, don't.
+ if (isSpecialUserId(userId)) {
+ // For secure password storage (that is required for special users such as FRP), the
+ // underlying storage also enforces the deadline. Since we cannot store settings
+ // for special users, don't.
return deadline;
}
mLockoutDeadlines.put(userId, deadline);
@@ -1822,6 +1850,64 @@
}
/**
+ * Return {@code true} if repair mode is supported by the device.
+ */
+ public static boolean isRepairModeSupported(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_repairModeSupported);
+ }
+
+ /**
+ * Return {@code true} if repair mode is active on the device.
+ */
+ public static boolean isRepairModeActive(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REPAIR_MODE_ACTIVE, /* def= */ 0) > 0;
+ }
+
+ /**
+ * Return {@code true} if repair mode is supported by the device and the user has been granted
+ * admin privileges.
+ */
+ public static boolean canUserEnterRepairMode(Context context, UserInfo info) {
+ return info != null && info.isAdmin() && isRepairModeSupported(context);
+ }
+
+ /**
+ * Return {@code true} if GSI is running on the device.
+ */
+ public static boolean isGsiRunning() {
+ return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
+ }
+
+ /**
+ * Return {@code true} if the given user id is a special user such as {@link #USER_FRP}.
+ */
+ public static boolean isSpecialUserId(int userId) {
+ return isSpecialUserId(/* context= */ null, userId, /* checkDeviceSupported= */ false);
+ }
+
+ /**
+ * Return {@code true} if the given user id is a special user for the verification flow.
+ *
+ * @param checkDeviceSupported {@code true} to check the specified user is supported
+ * by the device.
+ */
+ private static boolean isSpecialUserId(@Nullable Context context, int userId,
+ boolean checkDeviceSupported) {
+ switch (userId) {
+ case USER_FRP:
+ if (checkDeviceSupported) return frpCredentialEnabled(context);
+ return true;
+
+ case USER_REPAIR_MODE:
+ if (checkDeviceSupported) return isRepairModeSupported(context);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Attempt to rederive the unified work challenge for the specified profile user and unlock the
* user. If successful, this would allow the user to leave quiet mode automatically without
* additional user authentication.
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index da24af3..c2cfcd6 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1509,6 +1509,8 @@
int resultColor = ColorUtils.blendARGB(mDotColor, mDotActivatedColor,
/* ratio= */ activationAnimationProgress);
mPaint.setColor(resultColor);
+ } else if (!mFadePattern && partOfPattern){
+ mPaint.setColor(mDotActivatedColor);
} else {
mPaint.setColor(getDotColor());
}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index fb4b026..e65b4b6 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -359,20 +359,16 @@
// Draw current touch ellipse.
mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128);
- drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor * mDensity,
- ps.mCoords.touchMinor * mDensity, ps.mCoords.orientation, mPaint);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor,
+ ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint);
// Draw current tool ellipse.
mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel);
- drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor * mDensity,
- ps.mCoords.toolMinor * mDensity, ps.mCoords.orientation, mPaint);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor,
+ ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint);
- // Draw the orientation arrow.
- float arrowSize = ps.mCoords.toolMajor * 0.7f;
- if (arrowSize < 20) {
- arrowSize = 20;
- }
- arrowSize *= mDensity;
+ // Draw the orientation arrow, and ensure it has a minimum size of 24dp.
+ final float arrowSize = Math.max(ps.mCoords.toolMajor * 0.7f, 24 * mDensity);
mPaint.setARGB(255, pressureLevel, 255, 0);
float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation)
* arrowSize);
diff --git a/core/java/com/android/internal/widget/ViewGroupFader.java b/core/java/com/android/internal/widget/ViewGroupFader.java
new file mode 100644
index 0000000..b54023a
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewGroupFader.java
@@ -0,0 +1,315 @@
+/*
+ * 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.internal.widget;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * This class is ported from
+ * com.google.android.clockwork.common.wearable.wearmaterial.list.ViewGroupFader with minor
+ * modifications set the opacity of the views during animation (uses setTransitionAlpha on the view
+ * instead of setLayerType as the latter doesn't play nicely with a dialog. See - b/193583546)
+ *
+ * Fades of the children of a {@link ViewGroup} in and out, based on the position of the child.
+ *
+ * <p>Children are "faded" when they lie entirely in a region on the top and bottom of a {@link
+ * ViewGroup}. This region is sized as a fraction of the {@link ViewGroup}'s height, based on the
+ * height of the child. When not in the top or bottom regions, children have their default alpha and
+ * scale.
+ */
+class ViewGroupFader {
+
+ private static final float SCALE_LOWER_BOUND = 0.7f;
+ private float mScaleLowerBound = SCALE_LOWER_BOUND;
+
+ private static final float ALPHA_LOWER_BOUND = 0.5f;
+ private float mAlphaLowerBound = ALPHA_LOWER_BOUND;
+
+ private static final float CHAINED_BOUNDS_TOP_FRACTION = 0.6f;
+ private static final float CHAINED_BOUNDS_BOTTOM_FRACTION = 0.2f;
+ private static final float CHAINED_LOWER_REGION_FRACTION = 0.35f;
+ private static final float CHAINED_UPPER_REGION_FRACTION = 0.55f;
+
+ private float mChainedBoundsTop = CHAINED_BOUNDS_TOP_FRACTION;
+ private float mChainedBoundsBottom = CHAINED_BOUNDS_BOTTOM_FRACTION;
+ private float mChainedLowerRegion = CHAINED_LOWER_REGION_FRACTION;
+ private float mChainedUpperRegion = CHAINED_UPPER_REGION_FRACTION;
+
+ protected final ViewGroup mParent;
+
+ private final Rect mContainerBounds = new Rect();
+ private final Rect mOffsetViewBounds = new Rect();
+ private final AnimationCallback mCallback;
+ private final ChildViewBoundsProvider mChildViewBoundsProvider;
+
+ private ContainerBoundsProvider mContainerBoundsProvider;
+ private float mTopBoundPixels;
+ private float mBottomBoundPixels;
+ private BaseInterpolator mTopInterpolator = new PathInterpolator(0.3f, 0f, 0.7f, 1f);
+ private BaseInterpolator mBottomInterpolator = new PathInterpolator(0.3f, 0f, 0.7f, 1f);
+
+ /** Callback which is called when attempting to fade a view. */
+ interface AnimationCallback {
+ boolean shouldFadeFromTop(View view);
+
+ boolean shouldFadeFromBottom(View view);
+
+ void viewHasBecomeFullSize(View view);
+ }
+
+ /**
+ * Interface for providing the bounds of the child views. This is needed because for
+ * RecyclerViews, we might need to use bounds that represents the post-layout position, instead
+ * of the current position.
+ */
+ // TODO(b/182846214): Clean up the interface design to avoid exposing too much details to users.
+ interface ChildViewBoundsProvider {
+ /**
+ * Provide the bounds of the child view.
+ *
+ * @param parent the parent container.
+ * @param child the child view.
+ * @param bounds the bounds of the child view. The bounds are relative to
+ * the value of the bounds for setContainerBoundsProvider. By default,
+ * this is relative to the screen.
+ */
+ void provideBounds(ViewGroup parent, View child, Rect bounds);
+ }
+
+ /** Interface for providing the bounds of the container for use in calculating item fades. */
+ interface ContainerBoundsProvider {
+ /**
+ * Provide the bounds of the container for use in calculating item fades.
+ *
+ * @param parent the parent of the container.
+ * @param bounds the baseline bounds to which the child bounds are relative.
+ */
+ void provideBounds(ViewGroup parent, Rect bounds);
+ }
+
+ /**
+ * Implementation of {@link ContainerBoundsProvider} that returns the screen bounds as the
+ * container that is used for calculating the animation of the child elements in the ViewGroup.
+ */
+ static final class ScreenContainerBoundsProvider implements ContainerBoundsProvider {
+ @Override
+ public void provideBounds(ViewGroup parent, Rect bounds) {
+ bounds.set(
+ 0,
+ 0,
+ parent.getResources().getDisplayMetrics().widthPixels,
+ parent.getResources().getDisplayMetrics().heightPixels);
+ }
+ }
+
+ /**
+ * Implementation of {@link ContainerBoundsProvider} that returns the parent ViewGroup bounds as
+ * the container that is used for calculating the animation of the child elements in the
+ * ViewGroup.
+ */
+ static final class ParentContainerBoundsProvider implements ContainerBoundsProvider {
+ @Override
+ public void provideBounds(ViewGroup parent, Rect bounds) {
+ parent.getGlobalVisibleRect(bounds);
+ }
+ }
+
+ /**
+ * Default implementation of {@link ChildViewBoundsProvider} that returns the post-layout
+ * bounds of the child view. This should be used when the {@link ViewGroupFader} is used
+ * together with a RecyclerView.
+ */
+ static final class DefaultViewBoundsProvider implements ChildViewBoundsProvider {
+ @Override
+ public void provideBounds(ViewGroup parent, View child, Rect bounds) {
+ child.getDrawingRect(bounds);
+ bounds.offset(0, (int) child.getTranslationY());
+ parent.offsetDescendantRectToMyCoords(child, bounds);
+
+ // Additionally offset the bounds based on parent container's absolute position.
+ Rect parentGlobalVisibleBounds = new Rect();
+ parent.getGlobalVisibleRect(parentGlobalVisibleBounds);
+ bounds.offset(parentGlobalVisibleBounds.left, parentGlobalVisibleBounds.top);
+ }
+ }
+
+ /**
+ * Implementation of {@link ChildViewBoundsProvider} that returns the global visible bounds of
+ * the child view. This should be used when the {@link ViewGroupFader} is not used together with
+ * a RecyclerView.
+ */
+ static final class GlobalVisibleViewBoundsProvider implements ChildViewBoundsProvider {
+ @Override
+ public void provideBounds(ViewGroup parent, View child, Rect bounds) {
+ // Get the absolute position of the child. Normally we'd need to also reset the
+ // transformation matrix before computing this, but the transformations we apply set
+ // a pivot that preserves the coordinate of the top/bottom boundary used to compute the
+ // scaling factor in the first place.
+ child.getGlobalVisibleRect(bounds);
+ }
+ }
+
+ ViewGroupFader(
+ ViewGroup parent,
+ AnimationCallback callback,
+ ChildViewBoundsProvider childViewBoundsProvider) {
+ this.mParent = parent;
+ this.mCallback = callback;
+ this.mChildViewBoundsProvider = childViewBoundsProvider;
+ this.mContainerBoundsProvider = new ScreenContainerBoundsProvider();
+ }
+
+ AnimationCallback getAnimationCallback() {
+ return mCallback;
+ }
+
+ /**
+ * Sets the lower bound of the scale the view can reach, on a scale of 0 to 1.
+ *
+ * @param scale the value for the lower bound of the scale.
+ */
+ void setScaleLowerBound(float scale) {
+ mScaleLowerBound = scale;
+ }
+
+ /**
+ * Sets the lower bound of the alpha the view can reach, on a scale of 0 to 1.
+ *
+ * @param alpha the value for the lower bound of the alpha.
+ */
+ void setAlphaLowerBound(float alpha) {
+ mAlphaLowerBound = alpha;
+ }
+
+ void setTopInterpolator(BaseInterpolator interpolator) {
+ this.mTopInterpolator = interpolator;
+ }
+
+ void setBottomInterpolator(BaseInterpolator interpolator) {
+ this.mBottomInterpolator = interpolator;
+ }
+
+ void setContainerBoundsProvider(ContainerBoundsProvider boundsProvider) {
+ this.mContainerBoundsProvider = boundsProvider;
+ }
+
+ void updateFade() {
+ mContainerBoundsProvider.provideBounds(mParent, mContainerBounds);
+ mTopBoundPixels = mContainerBounds.height() * mChainedBoundsTop;
+ mBottomBoundPixels = mContainerBounds.height() * mChainedBoundsBottom;
+
+ updateListElementFades(mParent, true);
+ }
+
+ /** For each list element, calculate and adjust the scale and alpha based on its position */
+ private void updateListElementFades(ViewGroup parent, boolean shouldFade) {
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ View child = parent.getChildAt(i);
+ if (child.getVisibility() != View.VISIBLE) {
+ continue;
+ }
+
+ if (shouldFade) {
+ fadeElement(parent, child);
+ }
+ }
+ }
+
+ private void fadeElement(ViewGroup parent, View child) {
+ mChildViewBoundsProvider.provideBounds(parent, child, mOffsetViewBounds);
+ setViewPropertiesByPosition(child, mOffsetViewBounds, mTopBoundPixels, mBottomBoundPixels);
+ }
+
+ /** Set the bounds and change the view's scale and alpha accordingly */
+ private void setViewPropertiesByPosition(
+ View view, Rect bounds, float topBoundPixels, float bottomBoundPixels) {
+ float fadeOutRegionFraction;
+ if (view.getHeight() < topBoundPixels && view.getHeight() > bottomBoundPixels) {
+ // Scale from LOWER_REGION_FRACTION to UPPER_REGION_FRACTION based on the ratio of view
+ // height to chain region height.
+ fadeOutRegionFraction = lerp(
+ mChainedLowerRegion,
+ mChainedUpperRegion,
+ (view.getHeight() - bottomBoundPixels) / (topBoundPixels - bottomBoundPixels));
+ } else if (view.getHeight() < bottomBoundPixels) {
+ fadeOutRegionFraction = mChainedLowerRegion;
+ } else {
+ fadeOutRegionFraction = mChainedUpperRegion;
+ }
+ int fadeOutRegionHeight = (int) (mContainerBounds.height() * fadeOutRegionFraction);
+ int topFadeBoundary = fadeOutRegionHeight + mContainerBounds.top;
+ int bottomFadeBoundary = mContainerBounds.bottom - fadeOutRegionHeight;
+ boolean wasFullSize = (view.getScaleX() == 1);
+
+ MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
+ view.setPivotX(view.getWidth() * 0.5f);
+ if (bounds.top > bottomFadeBoundary && mCallback.shouldFadeFromBottom(view)) {
+ view.setPivotY((float) -lp.topMargin);
+ scaleAndFadeByRelativeOffsetFraction(
+ view,
+ mBottomInterpolator.getInterpolation(
+ (float) (mContainerBounds.bottom - bounds.top) / fadeOutRegionHeight));
+ } else if (bounds.bottom < topFadeBoundary && mCallback.shouldFadeFromTop(view)) {
+ view.setPivotY(view.getMeasuredHeight() + (float) lp.bottomMargin);
+ scaleAndFadeByRelativeOffsetFraction(
+ view,
+ mTopInterpolator.getInterpolation(
+ (float) (bounds.bottom - mContainerBounds.top) / fadeOutRegionHeight));
+ } else {
+ if (!wasFullSize) {
+ mCallback.viewHasBecomeFullSize(view);
+ }
+ setDefaultSizeAndAlphaForView(view);
+ }
+ }
+
+ /**
+ * Change the scale and opacity of the view based on its offset fraction to the
+ * determining bound.
+ */
+ private void scaleAndFadeByRelativeOffsetFraction(View view, float offsetFraction) {
+ float alpha = lerp(mAlphaLowerBound, 1, offsetFraction);
+ view.setTransitionAlpha(alpha);
+ float scale = lerp(mScaleLowerBound, 1, offsetFraction);
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ }
+
+ /** Set the scale and alpha of the view to the full default */
+ private void setDefaultSizeAndAlphaForView(View view) {
+ view.setTransitionAlpha(1f);
+ view.setScaleX(1f);
+ view.setScaleY(1f);
+ }
+
+ /**
+ * Linear interpolation between [min, max] using [fraction].
+ *
+ * @param min the starting point of the interpolation range.
+ * @param max the ending point of the interpolation range.
+ * @param fraction the proportion of the range to linearly interpolate for.
+ * @return the interpolated value.
+ */
+ private static float lerp(float min, float max, float fraction) {
+ return min + (max - min) * fraction;
+ }
+}
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index da21486..f3acab0 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -13,33 +13,186 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector android:height="128dp"
- android:width="128dp"
- android:viewportHeight="24"
- android:viewportWidth="24"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="512dp"
+ android:height="512dp"
+ android:viewportWidth="512"
+ android:viewportHeight="512">
+ <path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:startX="256"
+ android:startY="21.81"
+ android:endX="256"
+ android:endY="350.42"
+ android:type="linear">
+ <item android:offset="0" android:color="#FF073042"/>
+ <item android:offset="1" android:color="#FF073042"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
<path
- android:fillColor="@android:color/system_accent1_400"
- android:pathData="M11,0.3c0.6,-0.3 1.4,-0.3 2,0l0.6,0.4c0.7,0.4 1.4,0.6 2.2,0.6l0.7,-0.1c0.7,0 1.4,0.3 1.8,0.9l0.3,0.6c0.4,0.7 1,1.2 1.7,1.5L21,4.5c0.7,0.3 1.1,0.9 1.2,1.7v0.7C22.2,7.7 22.5,8.4 23,9l0.4,0.5c0.4,0.6 0.5,1.3 0.2,2l-0.3,0.6c-0.3,0.7 -0.4,1.5 -0.3,2.3l0.1,0.7c0.1,0.7 -0.2,1.4 -0.7,1.9L22,17.5c-0.6,0.5 -1.1,1.1 -1.3,1.9L20.5,20c-0.2,0.7 -0.8,1.2 -1.5,1.4l-0.7,0.1c-0.8,0.2 -1.4,0.5 -2,1.1l-0.5,0.5c-0.5,0.5 -1.3,0.7 -2,0.5l-0.6,-0.2c-0.8,-0.2 -1.5,-0.2 -2.3,0l-0.6,0.2c-0.7,0.2 -1.5,0 -2,-0.5l-0.5,-0.5c-0.5,-0.5 -1.2,-0.9 -2,-1.1L5,21.4c-0.7,-0.2 -1.3,-0.7 -1.5,-1.4l-0.2,-0.7C3.1,18.6 2.6,18 2,17.5l-0.6,-0.4c-0.6,-0.5 -0.8,-1.2 -0.7,-1.9l0.1,-0.7c0.1,-0.8 0,-1.6 -0.3,-2.3l-0.3,-0.6c-0.3,-0.7 -0.2,-1.4 0.2,-2L1,9c0.5,-0.6 0.7,-1.4 0.8,-2.2V6.2C1.9,5.5 2.3,4.8 3,4.5l0.6,-0.3c0.7,-0.3 1.3,-0.9 1.7,-1.5l0.3,-0.6c0.4,-0.6 1.1,-1 1.8,-0.9l0.7,0.1c0.8,0 1.6,-0.2 2.2,-0.6L11,0.3z"
- />
+ android:pathData="m195.27,187.64l2.25,-6.69c13.91,78.13 50.84,284.39 50.84,50.33 0,-0.97 0.72,-1.81 1.62,-1.81h12.69c0.9,0 1.62,0.83 1.62,1.8 -0.2,409.91 -69.03,-43.64 -69.03,-43.64Z"
+ android:fillColor="#3ddc84"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
<path
- android:pathData="M6.3,6.5l3,0l0,12.2"
- android:strokeWidth="2.22"
- android:strokeColor="@android:color/system_accent3_800"
- />
+ android:pathData="m158.77,180.68l-33.17,57.45c-1.9,3.3 -0.77,7.52 2.53,9.42 3.3,1.9 7.52,0.77 9.42,-2.53l33.59,-58.17c54.27,24.33 116.34,24.33 170.61,0l33.59,58.17c1.97,3.26 6.21,4.3 9.47,2.33 3.17,-1.91 4.26,-5.99 2.47,-9.23l-33.16,-57.45c56.95,-30.97 95.91,-88.64 101.61,-156.76H57.17c5.7,68.12 44.65,125.79 101.61,156.76Z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
<path
- android:pathData="M12.3,6.5h4l-2,4c2.2,0.3 3.6,2.4 3.3,4.5c-0.3,1.9 -1.9,3.3 -3.8,3.3c-0.5,0 -1,-0.1 -1.4,-0.3"
- android:strokeWidth="2.22"
- android:strokeColor="@android:color/system_accent3_800"
- />
+ android:pathData="M250.26,187.66L262.17,187.66A2.13,2.13 0,0 1,264.3 189.78L264.3,217.85A2.13,2.13 0,0 1,262.17 219.98L250.26,219.98A2.13,2.13 0,0 1,248.14 217.85L248.14,189.78A2.13,2.13 0,0 1,250.26 187.66z"
+ android:fillColor="#3ddc84"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
<path
- android:pathData="M6.3,6.5l3,0l0,12.2"
- android:strokeWidth="0.56"
- android:strokeColor="@android:color/system_neutral1_100"
- />
+ android:pathData="M250.12,170.29L262.32,170.29A1.98,1.98 0,0 1,264.3 172.26L264.3,176.39A1.98,1.98 0,0 1,262.32 178.37L250.12,178.37A1.98,1.98 0,0 1,248.14 176.39L248.14,172.26A1.98,1.98 0,0 1,250.12 170.29z"
+ android:fillColor="#3ddc84"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
<path
- android:pathData="M12.3,6.5h4l-2,4c2.2,0.3 3.6,2.4 3.3,4.5c-0.3,1.9 -1.9,3.3 -3.8,3.3c-0.5,0 -1,-0.1 -1.4,-0.3"
- android:strokeWidth="0.56"
- android:strokeColor="@android:color/system_neutral1_100"
- />
+ android:pathData="M171.92,216.82h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M188.8,275.73h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M369.04,337.63h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M285.93,252.22h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M318.96,218.84h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M294.05,288.55h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M330.82,273.31h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M188.8,298.95h4.04v4.04h-4.04z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M220.14,238.94h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M272.1,318.9h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M293.34,349.25h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M161.05,254.24h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M378.92,192h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <group>
+ <clip-path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
+ <path
+ android:pathData="M137.87,323.7h8.08v8.08h-8.08z"
+ android:fillColor="#fff"/>
+ </group>
+ <path
+ android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"
+ android:strokeWidth="56.561"
+ android:fillColor="#00000000"
+ android:strokeColor="#f86734"/>
+ <path
+ android:pathData="m256.22,126.57c-6.69,0 -12.12,5.27 -12.12,11.77v14.52c0,1.25 1.02,2.27 2.27,2.27h0c1.25,0 2.27,-1.02 2.27,-2.27v-3.91c0,-2.51 2.04,-4.55 4.55,-4.55h6.06c2.51,0 4.55,2.04 4.55,4.55v3.91c0,1.25 1.02,2.27 2.27,2.27s2.27,-1.02 2.27,-2.27v-14.52c0,-6.5 -5.43,-11.77 -12.12,-11.77Z"
+ android:fillColor="#3ddc84"/>
+ <path
+ android:pathData="m93.34,116.36l3.85,-4.36 29.64,9.76 -4.44,5.03 -6.23,-2.1 -7.86,8.91 2.86,5.92 -4.43,5.03 -13.39,-28.18ZM110.43,122.76l-8.86,-3.02 4.11,8.41 4.76,-5.39Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m153.62,100.85l-21.71,-6.2 10.38,14.38 -5.21,3.76 -16.78,-23.26 4.49,-3.24 21.65,6.19 -10.35,-14.35 5.24,-3.78 16.78,23.26 -4.49,3.24Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m161.46,63.15l8.99,-3.84c7.43,-3.18 15.96,0.12 19.09,7.44 3.13,7.32 -0.38,15.76 -7.81,18.94l-8.99,3.84 -11.28,-26.38ZM179.41,80.26c4.46,-1.91 5.96,-6.72 4.15,-10.96 -1.81,-4.24 -6.33,-6.48 -10.79,-4.57l-3.08,1.32 6.64,15.53 3.08,-1.32Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m204.23,47.57l11.1,-2.2c5.31,-1.05 9.47,2.08 10.4,6.76 0.72,3.65 -0.76,6.37 -4.07,8.34l12.4,10.44 -7.57,1.5 -11.65,-9.76 -1.03,0.2 2.3,11.61 -6.3,1.25 -5.57,-28.14ZM216.78,56.7c1.86,-0.37 3,-1.71 2.68,-3.33 -0.34,-1.7 -1.88,-2.43 -3.74,-2.06l-4.04,0.8 1.07,5.39 4.04,-0.8Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m244.29,55.6c0.13,-8.16 6.86,-14.72 15.06,-14.58 8.16,0.13 14.72,6.9 14.58,15.06s-6.91,14.72 -15.06,14.58c-8.2,-0.13 -14.71,-6.9 -14.58,-15.06ZM267.44,55.98c0.08,-4.64 -3.54,-8.66 -8.18,-8.74 -4.68,-0.08 -8.42,3.82 -8.5,8.47 -0.08,4.65 3.54,8.66 8.22,8.74 4.64,0.08 8.39,-3.82 8.46,-8.47Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m294.39,44.84l6.31,1.23 -5.49,28.16 -6.31,-1.23 5.49,-28.16Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m321.94,51.41l9.14,3.48c7.55,2.88 11.39,11.17 8.56,18.61 -2.83,7.44 -11.22,11.07 -18.77,8.19l-9.14,-3.48 10.22,-26.8ZM322.96,76.19c4.53,1.73 8.95,-0.69 10.6,-5 1.64,-4.3 -0.05,-9.06 -4.58,-10.78l-3.13,-1.19 -6.01,15.78 3.13,1.19Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m381.41,89.24l-4.21,-3.21 3.65,-4.78 9.06,6.91 -17.4,22.81 -4.85,-3.7 13.75,-18.02Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="m397.96,126.37l-9.56,-10.26 3.61,-3.36 22.8,-1.25 3.74,4.02 -12.35,11.51 2.51,2.69 -4.08,3.8 -2.51,-2.69 -4.55,4.24 -4.16,-4.46 4.55,-4.24ZM407.83,117.17l-10.28,0.58 4.49,4.82 5.79,-5.4Z"
+ android:fillColor="#fff"/>
</vector>
+
diff --git a/core/res/res/layout-watch/watch_base_error_dialog.xml b/core/res/res/layout-watch/watch_base_error_dialog.xml
index 0f3fb42..c8ea017 100644
--- a/core/res/res/layout-watch/watch_base_error_dialog.xml
+++ b/core/res/res/layout-watch/watch_base_error_dialog.xml
@@ -19,7 +19,7 @@
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView
+ <com.android.internal.widget.FadingWearableScrollView
android:id="@+id/scrollView"
android:fillViewport="true"
android:layout_width="match_parent"
@@ -110,5 +110,5 @@
</LinearLayout>
</FrameLayout>
</LinearLayout>
- </ScrollView>
+ </com.android.internal.widget.FadingWearableScrollView>
</com.android.internal.widget.WatchListDecorLayout>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4f6c4f7e..5c222cd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"ይህ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"ይህ መተግበሪያ የተገነባው ለቆየ የAndroid ስሪት ነበር። በትክክል ላይሰራ ይችላል እና የቅርብ ጊዜዎቹን የደህንነት እና የግላዊነት ጥበቃዎች አያካትትም። ዝማኔ ካለ ይፈትሹ ወይም የመተግበሪያውን ገንቢ ያነጋግሩ።"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ዝማኔ ካለ አረጋግጥ"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"ይህ መተግበሪያ ከቅርብ ጊዜው የAndroid. ስሪት ጋር ተኳዃኝ አይደለም። ዝማኔ ካለ ይፈትሹ ወይም የመተግበሪያውን ገንቢ ያነጋግሩ።"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"አዲስ መልዕክቶች አለዎት"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"ለመመልከት የኤስኤምኤስ መተግበሪያ ይክፈቱ"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"አንዳንድ ተግባሮች የተገደቡ ሊሆኑ ይችላሉ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c586351..245902a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1981,8 +1981,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"لا يمكن الوصول إلى هذه الإعدادات على <xliff:g id="DEVICE">%1$s</xliff:g>. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"تم إنشاء هذا التطبيق لإصدار قديم من Android. قد لا يعمل بشكل صحيح كما أنه لا يشتمِل على أحدث الإجراءات لحماية الأمان والخصوصية. ابحث عن تحديث أو تواصَل مع مطوّر التطبيق."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن تحديث"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"هذا التطبيق غير متوافق مع أحدث إصدار من Android. ابحث عن تحديث أو تواصَل مع مطوّر التطبيق."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"لديك رسائل جديدة"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"فتح تطبيق الرسائل القصيرة SMS للعرض"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"قد تكون بعض الوظائف مُقيّدة."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e6a073a..a8c8566 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"এইটো আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"এই এপ্টো Androidৰ এটা পুৰণা সংস্কৰণৰ বাবে বনোৱা হৈছিল। এইটোৱে সঠিকভাৱে কাম নকৰিব পাৰে আৰু ইয়াত শেহতীয়া সুৰক্ষা আৰু গোপনীয়তা সম্পৰ্কীয় সুৰক্ষাসমূহ নাথাকে। কোনো আপডে’ট আছে নেকি চাওক অথবা এপৰ বিকাশকৰ্তাগৰাকীৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডে’ট আছে নেকি চাওক"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"এই এপ্টো Androidৰ শেহতীয়া সংস্কৰণটোৰ সৈতে সমিল নহয়। আপডে’ট আছে নেকি চাওক অথবা এপৰ বিকাশকৰ্তাগৰাকীৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"আপুনি নতুন বার্তা লাভ কৰিছে"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"চাবলৈ এছএমএছ এপ্ খোলক"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"কিছুমান কাৰ্যকাৰিতা সীমিত হ’ব পাৰে"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index e7e9add..3b7eae5 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1979,8 +1979,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Не ўдаецца атрымаць доступ з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць тэлефон."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Гэта праграма створана для ранейшай версіі Android. Яна можа кепска працаваць, і ў ёй няма новых сродкаў абароны бяспекі і прыватнасці. Праверце наяўнасць абнаўленняў ці звярніцеся да распрацоўшчыка праграмы."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Праверыць наяўнасць абнаўленняў"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Гэтая праграма несумяшчальная з апошняй версіяй Android. Праверце наяўнасць абнаўленняў ці звярніцеся да распрацоўшчыка праграмы."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас ёсць новыя паведамленні"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Праглядзець праз праграму для SMS"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Функцыі могуць быць абмежаваныя"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 1c3c9d5..a1d2739 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1952,7 +1952,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ist momentan nicht verfügbar. Dies wird über die App \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\" verwaltet."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Weitere Informationen"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App-Pausierung aufheben"</string>
- <string name="work_mode_off_title" msgid="6367463960165135829">"Geschäftl. Apps nicht mehr pausieren?"</string>
+ <string name="work_mode_off_title" msgid="6367463960165135829">"Geschäftliche Apps nicht mehr pausieren?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Nicht mehr pausieren"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Notruf"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2f3ce75..1aeff38 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2174,7 +2174,7 @@
<string name="miniresolver_sms_information" msgid="4311292661329483088">"Teie organisatsioon lubab sõnumeid saata ainult töörakendustest."</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Kasuta isiklikku brauserit"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Kasuta tööbrauserit"</string>
- <string name="miniresolver_call" msgid="6386870060423480765">"Helistage"</string>
+ <string name="miniresolver_call" msgid="6386870060423480765">"Helista"</string>
<string name="miniresolver_switch" msgid="8011924662117617451">"Lülitu"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM-kaardi võrgu avamise PIN-kood"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY" msgid="7164399703751688214">"SIM-kaardi võrgu alamhulga avamise PIN-kood"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 375d456..03ee191 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> به این مورد دسترسی داشت. دسترسی به آن را در تلفنتان امتحان کنید."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"این برنامه برای نسخه قدیمیتری از Android ساخته شده است. احتمال دارد بهدرستی کار نکند و شامل جدیدترین محافظتهای حریم خصوصی و امنیت نمیشود. بررسی کنید بهروزرسانی دردسترس باشد یا با توسعهدهنده برنامه تماس بگیرید."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"بررسی وجود بهروزرسانی"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"این برنامه با جدیدترین نسخه Android سازگار نیست. بررسی کنید بهروزرسانی دردسترس باشد یا با توسعهدهنده برنامه تماس بگیرید."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"پیامهای جدیدی دارید"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"برای مشاهده، برنامه پیامک را باز کنید"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"برخی از عملکردها ممکن است محدود باشند"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b1c3fbb..452bbca 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1978,8 +1978,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre téléphone à la place."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Cette application a été conçue pour une ancienne version d\'Android. Elle pourrait ne pas fonctionner correctement, et ne comprend pas les dernières protections des données confidentielles et de sécurité. Vérifiez s\'il existe une mise à jour ou contactez le développeur de l\'application."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Cette application n\'est pas compatible avec la dernière version d\'Android. Vérifiez s\'il existe une mise à jour ou communiquez avec le développeur de l\'application."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Ouvrez l\'application de messagerie texte pour l\'afficher"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Des fonctionnalités sont limitées"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b0209b7..9095932 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Non se puido acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Esta aplicación deseñouse para unha versión anterior de Android. Quizais non funcione correctamente e non inclúa as últimas medidas de protección de privacidade e seguranza. Comproba se hai actualizacións ou ponte en contacto co programador da aplicación."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Esta aplicación non é compatible coa última versión de Android. Comproba se hai actualizacións ou ponte en contacto co programador da aplicación."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tes mensaxes novas"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Abre a aplicación de SMS para ver as mensaxes"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Pode haber funcións limitadas"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index cd7676e..03e1bde 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Androidના કોઈ જૂના વર્ઝન માટે આ ઍપ બનાવવામાં આવી હતી. તે કદાચ યોગ્ય રીતે કામ કરતી નથી અને તેમાં નવીનતમ સુરક્ષા અને પ્રાઇવસી સંબંધિત સંરક્ષણો શામેલ નથી. કોઈ અપડેટ ચેક કરો અથવા ઍપના ડેવલપરનો સંપર્ક કરો."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"અપડેટ માટે તપાસો"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"આ ઍપ Androidના નવીનતમ વર્ઝન સાથે સુસંગત નથી. કોઈ અપડેટ ચેક કરો અથવા ઍપના ડેવલપરનો સંપર્ક કરો."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"તમારી પાસે નવા સંદેશા છે"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"જોવા માટે SMS ઍપ્લિકેશન ખોલો"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"કેટલીક કાર્યક્ષમતા મર્યાદિત હોઈ શકે છે"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 8a3e772..78f5b6f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1978,8 +1978,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na telefonu."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Ova je aplikacija razvijena za stariju verziju Androida. Možda neće funkcionirati pravilno i ne uključuje najnovije zaštite sigurnosti i privatnosti. Provjerite je li za tu aplikaciju dostupno ažuriranje ili se obratite razvojnom programeru."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri ažuriranja"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Aplikacija nije kompatibilna s najnovijom verzijom Androida. Provjerite je li za tu aplikaciju dostupno ažuriranje ili se obratite razvojnom programeru."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Otvorite SMS aplikaciju da biste pregledali poruke"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Funkcije mogu biti ograničene"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 715f828..e6adbce 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -683,8 +683,8 @@
<string name="face_acquired_too_dark" msgid="8539853432479385326">"Թույլ լուսավորություն"</string>
<string name="face_acquired_too_close" msgid="4453646176196302462">"Փոքր-ինչ հեռու պահեք հեռախոսը"</string>
<string name="face_acquired_too_far" msgid="2922278214231064859">"Մոտեցրեք հեռախոսը"</string>
- <string name="face_acquired_too_high" msgid="8278815780046368576">"Բարձրացրեք հեռախոսը"</string>
- <string name="face_acquired_too_low" msgid="4075391872960840081">"Իջեցրեք հեռախոսը"</string>
+ <string name="face_acquired_too_high" msgid="8278815780046368576">"Պահեք հեռախոսն ավելի վերև"</string>
+ <string name="face_acquired_too_low" msgid="4075391872960840081">"Պահեք հեռախոսն ավելի ներքև"</string>
<string name="face_acquired_too_right" msgid="6245286514593540859">"Հեռախոսը շարժեք դեպի ձախ"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"Հեռախոսը շարժեք դեպի աջ"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Նայեք ուղիղ էկրանին։"</string>
@@ -1372,7 +1372,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">"Հպեք՝ անջատելու համար"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Հպեք անջատելու համար"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Սեղմեք՝ USB-ով վրիպազերծումն անջատելու համար:"</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Անլար վրիպազերծումը միացված է"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Հպեք՝ անլար վրիպազերծումն անջատելու համար"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f0d50ce..046d872 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -689,7 +689,7 @@
<string name="face_acquired_too_right" msgid="6245286514593540859">"צריך להזיז את הטלפון שמאלה"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"צריך להזיז את הטלפון ימינה"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"יש להביט ישירות אל המכשיר."</string>
- <string name="face_acquired_not_detected" msgid="1057966913397548150">"אי אפשר לראות את הפנים שלך. יש להחזיק את הטלפון בגובה העיניים."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"כדי לראות את הפנים שלך יש להחזיק את הטלפון בגובה העיניים."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"יותר מדי תנועה. יש להחזיק את הטלפון בצורה יציבה."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"יש לסרוק שוב את הפנים."</string>
<string name="face_acquired_too_different" msgid="2520389515612972889">"לא ניתן לזהות את הפנים. יש לנסות שוב."</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 68a21c1..0a0a813 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2174,7 +2174,7 @@
<string name="miniresolver_sms_information" msgid="4311292661329483088">"თქვენი ორგანიზაცია ნებას გრთავთ, მხოლოდ სამსახურის აპებიდან გაგზავნოთ შეტყობინებები"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"პირადი ბრაუზერის გამოყენება"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"სამსახურის ბრაუზერის გამოყენება"</string>
- <string name="miniresolver_call" msgid="6386870060423480765">"ზარი"</string>
+ <string name="miniresolver_call" msgid="6386870060423480765">"დარეკვა"</string>
<string name="miniresolver_switch" msgid="8011924662117617451">"გადართვა"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM ქსელის განბლოკვის PIN-კოდი"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY" msgid="7164399703751688214">"SIM ქსელის ქვედანაყოფის განბლოკვის PIN-კოდი"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 44f325c..949b32c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1717,7 +1717,7 @@
<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> សូមចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់ម្ដងទៀតរយៈពេល 3 វិនាទី។"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0c38ad1..20de6ab 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1717,7 +1717,7 @@
<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>을 켜려면 볼륨 키 2개를 3초 동안 길게 누르세요."</string>
@@ -2170,8 +2170,8 @@
<string name="miniresolver_open_in_work" msgid="941341494673509916">"직장 <xliff:g id="APP">%s</xliff:g> 앱에서 여시겠습니까?"</string>
<string name="miniresolver_call_in_work" msgid="528779988307529039">"직장 앱을 사용한 통화인가요?"</string>
<string name="miniresolver_switch_to_work" msgid="1042640606122638596">"직장 앱으로 전환할까요?"</string>
- <string name="miniresolver_call_information" msgid="6739417525304184083">"귀하의 조직에서 직장 앱을 사용한 통화만 허용했습니다."</string>
- <string name="miniresolver_sms_information" msgid="4311292661329483088">"귀하의 조직에서 직장 앱을 사용한 메시지 전송만 허용했습니다."</string>
+ <string name="miniresolver_call_information" msgid="6739417525304184083">"귀하의 조직에서 직장 앱을 사용한 통화만 허용합니다."</string>
+ <string name="miniresolver_sms_information" msgid="4311292661329483088">"귀하의 조직에서 직장 앱을 사용한 메시지 전송만 허용합니다."</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"개인 브라우저 사용"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"직장 브라우저 사용"</string>
<string name="miniresolver_call" msgid="6386870060423480765">"통화"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d2c6d3fb..d2349cd 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2170,8 +2170,8 @@
<string name="miniresolver_open_in_work" msgid="941341494673509916">"ເປີດໃນ <xliff:g id="APP">%s</xliff:g> ສຳລັບວຽກບໍ?"</string>
<string name="miniresolver_call_in_work" msgid="528779988307529039">"ໂທຈາກແອັບບ່ອນເຮັດວຽກບໍ?"</string>
<string name="miniresolver_switch_to_work" msgid="1042640606122638596">"ສະຫຼັບໄປເປັນແອັບບ່ອນເຮັດວຽກບໍ?"</string>
- <string name="miniresolver_call_information" msgid="6739417525304184083">"ອົງການຈັດຕັ້ງຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານໂທຈາກແອັບບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
- <string name="miniresolver_sms_information" msgid="4311292661329483088">"ອົງການຈັດຕັ້ງຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານສົ່ງຂໍ້ຄວາມໄດ້ຈາກແອັບບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
+ <string name="miniresolver_call_information" msgid="6739417525304184083">"ອົງການຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານໂທຈາກແອັບບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
+ <string name="miniresolver_sms_information" msgid="4311292661329483088">"ອົງການຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານສົ່ງຂໍ້ຄວາມໄດ້ຈາກແອັບບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບສ່ວນຕົວ"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"ໃຊ້ໂປຣແກຣມທ່ອງເວັບບ່ອນເຮັດວຽກ"</string>
<string name="miniresolver_call" msgid="6386870060423480765">"ໂທ"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5619862..5edbf88 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1978,8 +1978,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ierīcē <xliff:g id="DEVICE">%1$s</xliff:g> nevar piekļūt šai funkcijai. Mēģiniet tai piekļūt tālrunī."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Šī lietotne ir paredzēta vecākai Android versijai. Tā var nedarboties pareizi un neietver jaunākās drošības un konfidencialitātes aizsardzības funkcijas. Pārbaudiet atjauninājumu pieejamību vai sazinieties ar lietotnes izstrādātāju."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Meklēt atjauninājumu"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Šī lietotne nav saderīga ar jaunāko Android versiju. Pārbaudiet atjauninājumu pieejamību vai sazinieties ar lietotnes izstrādātāju."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Jums ir jaunas īsziņas."</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Lai skatītu, atveriet īsziņu lietotni."</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Funkcijas var būt ierobežotas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b399d2b..acaea7e28 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на вашиот телефон како алтернатива."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Оваа апликација е создадена за постара верзија на Android. Можеби нема да работи правилно и не ги вклучува најновите мерки за заштита на безбедноста и приватноста. Проверете дали има ажурирање или контактирајте со програмерот на апликацијата."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за ажурирање"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Апликацијава не е компатибилна со најновата верзија на Android. Проверете дали има ажурирање или контактирајте со програмерот на апликацијата."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови пораки"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Отворете ја апликацијата за SMS за приказ"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Некои функции се ограничени"</string>
@@ -2171,8 +2170,8 @@
<string name="miniresolver_open_in_work" msgid="941341494673509916">"Да се отвори во работната апликација <xliff:g id="APP">%s</xliff:g>?"</string>
<string name="miniresolver_call_in_work" msgid="528779988307529039">"Да се повика од работна апликација?"</string>
<string name="miniresolver_switch_to_work" msgid="1042640606122638596">"Да се префрли на работна апликација?"</string>
- <string name="miniresolver_call_information" msgid="6739417525304184083">"Вашата организацијата ви дозволува да упатувате повици само од работни апликации"</string>
- <string name="miniresolver_sms_information" msgid="4311292661329483088">"Вашата организацијата ви дозволува да испраќате пораки само од работни апликации"</string>
+ <string name="miniresolver_call_information" msgid="6739417525304184083">"Вашата организација ви дозволува да упатувате повици само од работни апликации"</string>
+ <string name="miniresolver_sms_information" msgid="4311292661329483088">"Вашата организација ви дозволува да испраќате пораки само од работни апликации"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Користи личен прелистувач"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"Користи работен прелистувач"</string>
<string name="miniresolver_call" msgid="6386870060423480765">"Повикај"</string>
@@ -2333,7 +2332,7 @@
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двојниот екран е недостапен бидејќи вашиот телефон станува претопол"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"„Двојниот екран“ е недостапен"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Двојниот екран е недостапен бидејќи е вклучен „Штедач на батерија“. Ова може да се исклучи во „Поставки“."</string>
- <string name="device_state_notification_settings_button" msgid="691937505741872749">"Одете во „Поставките“"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Отворете „Поставки“"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Исклучи"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> е конфигуриран"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Распоредот на тастатурата е поставен на <xliff:g id="LAYOUT_1">%s</xliff:g>. Допрете за да промените."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index e472e51..475abe5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2170,8 +2170,8 @@
<string name="miniresolver_open_in_work" msgid="941341494673509916">"कामसम्बन्धी <xliff:g id="APP">%s</xliff:g> मा खोल्ने हो?"</string>
<string name="miniresolver_call_in_work" msgid="528779988307529039">"कामसम्बन्धी एपबाट कल गर्ने हो?"</string>
<string name="miniresolver_switch_to_work" msgid="1042640606122638596">"कामसम्बन्धी एप प्रयोग गर्ने हो?"</string>
- <string name="miniresolver_call_information" msgid="6739417525304184083">"तपाईंको सङ्गठनले तपाईंलाई कामसम्बन्धी एपहरूमार्फत मात्र कल गर्ने अनुमति दिन्छ"</string>
- <string name="miniresolver_sms_information" msgid="4311292661329483088">"तपाईंको सङ्गठनले तपाईंलाई कामसम्बन्धी एपहरूमार्फत मात्र म्यासेज पठाउने अनुमति दिन्छ"</string>
+ <string name="miniresolver_call_information" msgid="6739417525304184083">"तपाईंको सङ्गठनले तपाईंलाई कामसम्बन्धी एपहरूमार्फत मात्र कल गर्ने अनुमति दिएको छ"</string>
+ <string name="miniresolver_sms_information" msgid="4311292661329483088">"तपाईंको सङ्गठनले तपाईंलाई कामसम्बन्धी एपहरूमार्फत मात्र म्यासेज पठाउने अनुमति दिएको छ"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"व्यक्तिगत ब्राउजर प्रयोग गर्नुहोस्"</string>
<string name="miniresolver_use_work_browser" msgid="543575306251952994">"कार्य ब्राउजर प्रयोग गर्नुहोस्"</string>
<string name="miniresolver_call" msgid="6386870060423480765">"कल गर्नुहोस्"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 725d892..24549569 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1609,7 +1609,7 @@
<string name="fingerprints" msgid="148690767172613723">"ଆଙ୍ଗୁଠି ଚିହ୍ନ:"</string>
<string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 ଆଙ୍ଗୁଠି ଚିହ୍ନ:"</string>
<string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 ଟିପଚିହ୍ନ:"</string>
- <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"ସମସ୍ତ ଦେଖନ୍ତୁ"</string>
+ <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"ଗତିବିଧି ଚୟନ କରନ୍ତୁ"</string>
<string name="share_action_provider_share_with" msgid="1904096863622941880">"ଏହାଙ୍କ ସହ ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="sending" msgid="206925243621664438">"ପଠାଯାଉଛି…"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 15887f7..04894f3 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1979,8 +1979,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte prístup k tomuto obsahu. Skúste použiť telefón."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Táto aplikácia bola vytvorená pre staršiu verziu Androidu. Nemusí správne fungovať a obsahovať najnovšie prvky zabezpečenia a ochrany súkromia. Skontrolujte dostupnosť aktualizácie alebo kontaktujte jej vývojára."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Skontrolovať dostupnosť aktualizácie"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Táto aplikácia nie je kompatibilná s najnovšou verziou Androidu. Skontrolujte dostupnosť aktualizácie alebo kontaktujte jej vývojára."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové správy."</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Otvorte aplikáciu pre SMS a zobrazte správu"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Niektoré funkcie môžu byť obmedzené"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cbe0ed8..bb0e700 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -155,7 +155,7 @@
<string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nuk u transferua"</string>
<string name="fcComplete" msgid="1080909484660507044">"Kodi i funksionit është i plotë."</string>
<string name="fcError" msgid="5325116502080221346">"Problem me lidhjen ose kod është i pavlefshëm."</string>
- <string name="httpErrorOk" msgid="6206751415788256357">"Në rregull!"</string>
+ <string name="httpErrorOk" msgid="6206751415788256357">"Në rregull"</string>
<string name="httpError" msgid="3406003584150566720">"Pati një gabim në rrjet."</string>
<string name="httpErrorLookup" msgid="3099834738227549349">"Nuk mundi ta gjente URL-në."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Skema e vërtetimit nuk mbështetet."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d3d9d22..413206e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1717,7 +1717,7 @@
<string name="color_correction_feature_name" msgid="7975133554160979214">"Färgkorrigering"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhandsläge"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradimmat"</string>
- <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörapparater"</string>
+ <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörhjälpmedel"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="3760999147597564314">"Släpp volymknapparna. Du kan aktivera <xliff:g id="SERVICE_NAME">%1$s</xliff:g> genom att hålla båda volymknapparna nedtryckta i tre sekunder igen."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 69c2b29..cf4273e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2169,7 +2169,7 @@
<string name="miniresolver_open_in_personal" msgid="807427577794490375">"Ungependa kufungua <xliff:g id="APP">%s</xliff:g> ukitumia wasifu wa binafsi?"</string>
<string name="miniresolver_open_in_work" msgid="941341494673509916">"Ungependa kufungua <xliff:g id="APP">%s</xliff:g> ukitumia wasifu wa kazini?"</string>
<string name="miniresolver_call_in_work" msgid="528779988307529039">"Ungependa kupiga simu ukitumia programu ya kazini?"</string>
- <string name="miniresolver_switch_to_work" msgid="1042640606122638596">"Ungependa kubadilisha ili utumie programu ya kazini?"</string>
+ <string name="miniresolver_switch_to_work" msgid="1042640606122638596">"Ungependa kutumia programu ya kazini?"</string>
<string name="miniresolver_call_information" msgid="6739417525304184083">"Shirika lako linakuruhusu upige simu ukitumia programu za kazini pekee"</string>
<string name="miniresolver_sms_information" msgid="4311292661329483088">"Shirika lako linakuruhusu utume ujumbe ukitumia programu za kazini pekee"</string>
<string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Tumia kivinjari cha binafsi"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a4865f5..13c45ed 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Bu uygulamaya <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Bu uygulama Android\'in daha eski bir sürümü için geliştirildi. Bu nedenle, düzgün çalışmayabilir ve son güvenlik ile gizlilik korumalarını içermemektedir. Güncelleme olup olmadığını kontrol edin veya uygulamanın geliştiricisiyle iletişime geçin."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncellemeleri denetle"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Bu uygulama Android\'in son sürümüyle uyumlu değil. Güncelleme olup olmadığını kontrol edin veya uygulamanın geliştiricisiyle iletişime geçin."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Görüntülemek için SMS uygulamasını açın"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Bazı işlevler sınırlanabilir"</string>
@@ -2169,7 +2168,7 @@
<string name="miniresolver_open_work" msgid="6286176185835401931">"İş uygulaması (<xliff:g id="APP">%s</xliff:g>) açılsın mı?"</string>
<string name="miniresolver_open_in_personal" msgid="807427577794490375">"Kişisel uygulamada (<xliff:g id="APP">%s</xliff:g>) açılsın mı?"</string>
<string name="miniresolver_open_in_work" msgid="941341494673509916">"İş uygulamasında (<xliff:g id="APP">%s</xliff:g>) açılsın mı?"</string>
- <string name="miniresolver_call_in_work" msgid="528779988307529039">"İş uygulamasından telefon edilsin mi?"</string>
+ <string name="miniresolver_call_in_work" msgid="528779988307529039">"İş uygulamasından aransın mı?"</string>
<string name="miniresolver_switch_to_work" msgid="1042640606122638596">"İş uygulamasına geçilsin mi?"</string>
<string name="miniresolver_call_information" msgid="6739417525304184083">"Kuruluşunuz yalnızca iş uygulamalarından telefon etmenize izin veriyor"</string>
<string name="miniresolver_sms_information" msgid="4311292661329483088">"Kuruluşunuz yalnızca iş uygulamalarından mesaj göndermenize izin veriyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6981327..4694c37 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1979,8 +1979,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Немає доступу на вашому пристрої (<xliff:g id="DEVICE">%1$s</xliff:g>). Спробуйте натомість скористатися телефоном."</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Цей додаток створено для старішої версії ОС Android. Він може не працювати належним чином і не містить найновіших засобів захисту конфіденційності та безпеки. Перевірте наявність оновлень або зв’яжіться з розробником додатка."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шукати оновлення"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"Цей додаток несумісний з останньою версією ОС Android. Перевірте наявність оновлень або зв’яжіться з розробником додатка."</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"У вас є нові повідомлення"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Щоб переглянути, відкрийте додаток для SMS"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Деякі функції може бути обмежено"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 274d02e..3a243c6 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1977,8 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی حاصل نہیں ہو سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"یہ ایپ Android کے پرانے ورژن کے لیے بنائی گئی تھی۔ ہو سکتا ہے یہ ٹھیک سے کام نہ کرے اور اس میں تازہ ترین سیکیورٹی اور رازداری کے تحفظات شامل نہ ہوں۔ اپ ڈیٹ کے لیے چیک کریں یا ایپ کے ڈویلپر سے رابطہ کریں۔"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"اپ ڈیٹ چیک کریں"</string>
- <!-- no translation found for deprecated_abi_message (6820548011196218091) -->
- <skip />
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"یہ ایپ Android کے تازہ ترین ورژن کے ساتھ مطابقت پذیر نہیں ہے۔ اپ ڈیٹ کے لیے چیک کریں یا ایپ کے ڈویلپر سے رابطہ کریں۔"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"آپ کے پاس نئے پیغامات ہیں"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"دیکھنے کیلئے SMS ایپ کھولیں"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"کچھ فعالیت محدود ہو سکتی ہے"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1249bbd..5bc8a88 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1977,7 +1977,7 @@
<string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用手機。"</string>
<string name="deprecated_target_sdk_message" msgid="5246906284426844596">"此應用程式專為舊版 Android 而設。因此可能無法正常運作,且不提供最新的安全性和私隱保護。請檢查是否有更新版本,或聯絡應用程式開發人員。"</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string>
- <string name="deprecated_abi_message" msgid="6820548011196218091">"這個應用程式與最新版的 Android 不相容。請檢查是否有可用的更新,或與應用程式發人員聯絡。"</string>
+ <string name="deprecated_abi_message" msgid="6820548011196218091">"此應用程式不兼容最新 Android 版本。請檢查是否有更新版本,或聯絡應用程式開發人員。"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"你有新的訊息"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"開啟短訊應用程式查看內容"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"部分功能可能會受到限制"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 28f3166..b55d263 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -461,10 +461,10 @@
<string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"允許應用程式修改平板電腦的通話記錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能刪除或修改你的通話記錄。"</string>
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"允許應用程式修改 Android TV 裝置的通話記錄,包括來電和撥出電話相關資料。惡意應用程式可能會藉此清除或修改你的通話記錄。"</string>
<string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"允許應用程式修改手機的通話記錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能刪除或修改你的通話記錄。"</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="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"允許應用程式在背景執行時存取人體感應器資料,例如心跳速率、體溫和血氧比例。"</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="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"允許應用程式在背景執行時存取人體感應器資料,例如心率、體溫和血氧比例。"</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"讀取日曆活動和詳細資訊"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"這個應用程式可讀取所有儲存在平板電腦上的日曆活動資訊,以及共用或儲存日曆資料。"</string>
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"這個應用程式可讀取所有儲存在 Android TV 裝置上的日曆活動,以及共用或儲存日曆資料。"</string>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 8420934..4ae54a0 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -167,4 +167,10 @@
true, routing from the android emergency number database will be ignored. -->
<bool name="ignore_emergency_number_routing_from_db">false</bool>
<java-symbol type="bool" name="ignore_emergency_number_routing_from_db" />
+
+ <!-- Boolean indicating whether allow sending null to modem to clear the previous initial attach
+ data profile -->
+ <bool name="allow_clear_initial_attach_data_profile">false</bool>
+ <java-symbol type="bool" name="allow_clear_initial_attach_data_profile" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e146522..2c72f45 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1795,6 +1795,8 @@
<string name="biometric_error_user_canceled">Authentication canceled</string>
<!-- Message shown by the biometric dialog when biometric is not recognized -->
<string name="biometric_not_recognized">Not recognized</string>
+ <!-- Message shown by the biometric dialog when face is not recognized [CHAR LIMIT=50] -->
+ <string name="biometric_face_not_recognized">Face not recognized</string>
<!-- Message shown when biometric authentication has been canceled [CHAR LIMIT=50] -->
<string name="biometric_error_canceled">Authentication canceled</string>
<!-- Message returned to applications if BiometricPrompt setAllowDeviceCredentials is enabled but no pin, pattern, or password is set. [CHAR LIMIT=NONE] -->
@@ -5041,8 +5043,8 @@
<string name="display_rotation_camera_compat_toast_after_rotation">Rotate for a better view</string>
<!-- Text on a toast shown when a camera view is started within the app that may not be able
- to display the camera preview correctly while in split screen. [CHAR LIMIT=NONE] -->
- <string name="display_rotation_camera_compat_toast_in_split_screen">Exit split screen for a better view</string>
+ to display the camera preview correctly while in multi-window. [CHAR LIMIT=NONE] -->
+ <string name="display_rotation_camera_compat_toast_in_multi_window">Open <xliff:g id="name" example="MyApp">%s</xliff:g> in full screen for a better view</string>
<!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
<string name="done_label">Done</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 16836fb..070004f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2545,7 +2545,7 @@
<java-symbol type="string" name="zen_mode_default_events_name" />
<java-symbol type="string" name="zen_mode_default_every_night_name" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
- <java-symbol type="string" name="display_rotation_camera_compat_toast_in_split_screen" />
+ <java-symbol type="string" name="display_rotation_camera_compat_toast_in_multi_window" />
<java-symbol type="array" name="config_system_condition_providers" />
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="zen_mode_alarm" />
@@ -2583,6 +2583,7 @@
<java-symbol type="string" name="biometric_error_hw_unavailable" />
<java-symbol type="string" name="biometric_error_user_canceled" />
<java-symbol type="string" name="biometric_not_recognized" />
+ <java-symbol type="string" name="biometric_face_not_recognized" />
<java-symbol type="string" name="biometric_error_canceled" />
<java-symbol type="string" name="biometric_error_device_not_secured" />
<java-symbol type="string" name="biometric_error_generic" />
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
index 436f058..85d54e0 100644
--- a/core/tests/BroadcastRadioTests/Android.bp
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -45,6 +45,7 @@
libs: ["android.test.base"],
test_suites: [
"general-tests",
+ "automotive-general-tests",
],
// mockito-target-inline dependency
jni_libs: [
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index b5f18c2..6ffdee1 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -45,7 +45,7 @@
@SmallTest
public void testGetEmpty() {
final Resources res = getActivity().getResources();
- assertNull(mCache.getInstance(-1, res, null).getValue());
+ assertNull(mCache.getInstance(-1, res, null));
}
@SmallTest
@@ -53,9 +53,9 @@
mCache.put(1, null, new DummyFloatConstantState(5f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(5f, mCache.getInstance(1, res, null).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, null).getValue());
- assertEquals(false, mCache.getInstance(1, res, getActivity().getTheme()).hasValue());
+ assertEquals(5f, mCache.getInstance(1, res, null));
+ assertNotSame(5f, mCache.getInstance(1, res, null));
+ assertEquals(null, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -63,9 +63,9 @@
mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(false, mCache.getInstance(1, res, null).hasValue());
- assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+ assertEquals(null, mCache.getInstance(1, res, null));
+ assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+ assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -75,10 +75,10 @@
mCache.put(1, null, new DummyFloatConstantState(10f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(10f, mCache.getInstance(1, res, null).getValue());
- assertNotSame(10f, mCache.getInstance(1, res, null).getValue());
- assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+ assertEquals(10f, mCache.getInstance(1, res, null));
+ assertNotSame(10f, mCache.getInstance(1, res, null));
+ assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+ assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -98,9 +98,9 @@
Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
- assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
mCache.onConfigurationChange(changes);
- assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
}
@SmallTest
@@ -123,9 +123,9 @@
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
assertEquals(changingDim,
- mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ mCache.getInstance(key, res, getActivity().getTheme()));
mCache.onConfigurationChange(changes);
- assertNull(mCache.get(key, getActivity().getTheme()).getValue());
+ assertNull(mCache.get(key, getActivity().getTheme()));
}
@SmallTest
@@ -152,15 +152,15 @@
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
assertEquals(changingDim,
mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
mCache.onConfigurationChange(changes);
assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
}
@SmallTest
@@ -198,18 +198,18 @@
for (int i = 0; i < 2; i++) {
final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
assertEquals(staticDim,
- mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+ mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
assertEquals(changingDim,
mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- theme).getValue());
+ theme));
}
mCache.onConfigurationChange(changes);
for (int i = 0; i < 2; i++) {
final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
assertEquals(staticDim,
- mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+ mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- theme).getValue());
+ theme));
}
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 89632a4..2a4ca79 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -25,8 +25,6 @@
import java.io.File;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -869,84 +867,90 @@
return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
}
- /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */
- public void testUnparcelLegacyPart_fails() throws Exception {
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part"));
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart"));
- }
-
- private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception {
- Parcel parcel = Parcel.obtain();
- parcel.writeInt(0 /* BOTH */);
- parcel.writeString("encoded");
- parcel.writeString("decoded");
- parcel.setDataPosition(0);
-
- Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class);
- readFromMethod.setAccessible(true);
- try {
- readFromMethod.invoke(null, parcel);
- fail();
- } catch (InvocationTargetException expected) {
- Throwable targetException = expected.getTargetException();
- // Check that the exception was thrown for the correct reason.
- assertEquals("Unknown representation: 0", targetException.getMessage());
- } finally {
- parcel.recycle();
- }
- }
-
- private Uri buildUriFromRawParcel(boolean argumentsEncoded,
+ private Uri buildUriFromParts(boolean argumentsEncoded,
String scheme,
String authority,
String path,
String query,
String fragment) {
- // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}).
- final int representation = argumentsEncoded ? 1 : 2;
- Parcel parcel = Parcel.obtain();
- try {
- parcel.writeInt(3); // hierarchical
- parcel.writeString8(scheme);
- parcel.writeInt(representation);
- parcel.writeString8(authority);
- parcel.writeInt(representation);
- parcel.writeString8(path);
- parcel.writeInt(representation);
- parcel.writeString8(query);
- parcel.writeInt(representation);
- parcel.writeString8(fragment);
- parcel.setDataPosition(0);
- return Uri.CREATOR.createFromParcel(parcel);
- } finally {
- parcel.recycle();
+ final Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (argumentsEncoded) {
+ builder.encodedAuthority(authority);
+ builder.encodedPath(path);
+ builder.encodedQuery(query);
+ builder.encodedFragment(fragment);
+ } else {
+ builder.authority(authority);
+ builder.path(path);
+ builder.query(query);
+ builder.fragment(fragment);
}
+ return builder.build();
}
public void testUnparcelMalformedPath() {
// Regression tests for b/171966843.
// Test cases with arguments encoded (covering testing `scheme` * `authority` options).
- Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
+ Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/@evil.com", uri0.toString());
- Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
+ Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x");
assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
- Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
+ Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString());
- Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
+ Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null);
assertEquals("@evil.com", uri3.toString());
// Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
- Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
+ Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/%40evil.com", uriA.toString());
- Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
+ Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null);
assertEquals("//google.com/%40evil.com", uriB.toString());
- Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
+ Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString());
- Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
+ Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
}
+ public void testParsedUriFromStringEquality() {
+ Uri uri = buildUriFromParts(
+ true, "https", "google.com", "@evil.com", null, null);
+ assertEquals(uri, Uri.parse(uri.toString()));
+ Uri uri2 = buildUriFromParts(
+ true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri2, Uri.parse(uri2.toString()));
+ Uri uri3 = buildUriFromParts(
+ false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri3, Uri.parse(uri3.toString()));
+ }
+
+ public void testParceledUrisAreEqual() {
+ Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment");
+ Parcel parcel = Parcel.obtain();
+ try {
+ opaqueUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+
+ Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build();
+ parcel = Parcel.obtain();
+ try {
+ hierarchicalUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+ }
+
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
diff --git a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
new file mode 100644
index 0000000..a84ac55
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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 android.service.notification;
+
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public class NotificationRankingUpdateTest {
+
+ private static final String NOTIFICATION_CHANNEL_ID = "test_channel_id";
+ private static final String TEST_KEY = "key";
+
+ private NotificationChannel mNotificationChannel;
+
+ // TODO(b/284297289): remove this flag set once resolved.
+ @Parameterized.Parameters(name = "rankingUpdateAshmem={0}")
+ public static Boolean[] getRankingUpdateAshmem() {
+ return new Boolean[] { true, false };
+ }
+
+ @Parameterized.Parameter
+ public boolean mRankingUpdateAshmem;
+
+ @Before
+ public void setUp() {
+ mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "test channel",
+ NotificationManager.IMPORTANCE_DEFAULT);
+
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = flag -> {
+ if (flag.mSysPropKey.equals(RANKING_UPDATE_ASHMEM.mSysPropKey)) {
+ return mRankingUpdateAshmem;
+ }
+ return new SystemUiSystemPropertiesFlags.DebugResolver().isEnabled(flag);
+ };
+ }
+
+ @After
+ public void tearDown() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
+ }
+
+ public NotificationListenerService.Ranking createTestRanking(String key, int rank) {
+ NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
+ ranking.populate(
+ /* key= */ key,
+ /* rank= */ rank,
+ /* matchesInterruptionFilter= */ false,
+ /* visibilityOverride= */ 0,
+ /* suppressedVisualEffects= */ 0,
+ mNotificationChannel.getImportance(),
+ /* explanation= */ null,
+ /* overrideGroupKey= */ null,
+ mNotificationChannel,
+ /* overridePeople= */ null,
+ /* snoozeCriteria= */ null,
+ /* showBadge= */ true,
+ /* userSentiment= */ 0,
+ /* hidden= */ false,
+ /* lastAudiblyAlertedMs= */ -1,
+ /* noisy= */ false,
+ /* smartActions= */ null,
+ /* smartReplies= */ null,
+ /* canBubble= */ false,
+ /* isTextChanged= */ false,
+ /* isConversation= */ false,
+ /* shortcutInfo= */ null,
+ /* rankingAdjustment= */ 0,
+ /* isBubble= */ false,
+ /* proposedImportance= */ 0,
+ /* sensitiveContent= */ false
+ );
+ return ranking;
+ }
+
+ @Test
+ public void testRankingUpdate_rankingConstructor() {
+ NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+ NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking});
+
+ NotificationListenerService.RankingMap retrievedRankings = rankingUpdate.getRankingMap();
+ NotificationListenerService.Ranking retrievedRanking =
+ new NotificationListenerService.Ranking();
+ assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
+ assertEquals(123, retrievedRanking.getRank());
+ }
+
+ @Test
+ public void testRankingUpdate_parcelConstructor() {
+ NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+ NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking});
+
+ Parcel parceledRankingUpdate = Parcel.obtain();
+ rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
+ parceledRankingUpdate.setDataPosition(0);
+
+ NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
+ parceledRankingUpdate);
+
+ NotificationListenerService.RankingMap retrievedRankings =
+ retrievedRankingUpdate.getRankingMap();
+ assertNotNull(retrievedRankings);
+ assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+ NotificationListenerService.Ranking retrievedRanking =
+ new NotificationListenerService.Ranking();
+ assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
+ assertEquals(123, retrievedRanking.getRank());
+ assertTrue(retrievedRankingUpdate.equals(rankingUpdate));
+ parceledRankingUpdate.recycle();
+ }
+
+ @Test
+ public void testRankingUpdate_emptyParcelInCheck() {
+ NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+ NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking});
+
+ Parcel parceledRankingUpdate = Parcel.obtain();
+ rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
+
+ // This will fail to read the parceledRankingUpdate, because the data position hasn't
+ // been reset, so it'll find no data to read.
+ NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
+ parceledRankingUpdate);
+ assertNull(retrievedRankingUpdate.getRankingMap());
+ }
+
+ @Test
+ public void testRankingUpdate_describeContents() {
+ NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+ NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking});
+ assertEquals(0, rankingUpdate.describeContents());
+ }
+
+ @Test
+ public void testRankingUpdate_equals() {
+ NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
+ NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking});
+ // Reflexive equality.
+ assertTrue(rankingUpdate.equals(rankingUpdate));
+ // Null or wrong class inequality.
+ assertFalse(rankingUpdate.equals(null));
+ assertFalse(rankingUpdate.equals(ranking));
+
+ // Different ranking contents inequality.
+ NotificationListenerService.Ranking ranking2 = createTestRanking(TEST_KEY, 456);
+ NotificationRankingUpdate rankingUpdate2 = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking2});
+ assertFalse(rankingUpdate.equals(rankingUpdate2));
+
+ // Same ranking contents equality.
+ ranking2 = createTestRanking(TEST_KEY, 123);
+ rankingUpdate2 = new NotificationRankingUpdate(
+ new NotificationListenerService.Ranking[]{ranking2});
+ assertTrue(rankingUpdate.equals(rankingUpdate2));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java b/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java
index e03b722..481993e5 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java
@@ -59,16 +59,6 @@
assertThat(AutofillFeatureFlags.isCredentialManagerEnabled()).isTrue();
}
- @Test
- public void testShouldIgnoreCredentialManagerViews() {
- setCredentialManagerEnabled(false);
- setIgnoreCredentialManagerViews(true);
- // Overall feature is disabled, so we shouldn't ignore views.
- assertThat(AutofillFeatureFlags.shouldIgnoreCredentialViews()).isFalse();
- setCredentialManagerEnabled(true);
- assertThat(AutofillFeatureFlags.shouldIgnoreCredentialViews()).isTrue();
- }
-
private static void setFillDialogHints(String value) {
setDeviceConfig(
AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
@@ -81,12 +71,6 @@
String.valueOf(value));
}
- private static void setIgnoreCredentialManagerViews(boolean value) {
- setDeviceConfig(
- AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS,
- String.valueOf(value));
- }
-
private static void setDeviceConfig(String key, String value) {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_AUTOFILL, key, value, /* makeDefault */ false);
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index f8ebd09..23b9b9b 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -32,6 +32,7 @@
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -130,6 +131,7 @@
() -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666}));
}
+ @Ignore("b/286134492")
@Test
public void testNotifyViewsDisappeared_noSendTreeEventBeforeU() {
MyContentCaptureSession session = new MyContentCaptureSession(121);
@@ -139,6 +141,7 @@
assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(0);
}
+ @Ignore("b/286134492")
@EnableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS})
@Test
public void testNotifyViewsDisappeared_sendTreeEventSinceU() {
@@ -151,7 +154,7 @@
@Test
public void testGetFlushReasonAsString() {
- int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED + 1;
+ int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED + 1;
Map<Integer, String> expectedMap =
new ImmutableMap.Builder<Integer, String>()
.put(ContentCaptureSession.FLUSH_REASON_FULL, "FULL")
@@ -168,8 +171,7 @@
.put(
ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED,
"VIEW_TREE_APPEARED")
- .put(ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED, "LOGIN_DETECTED")
- .put(invalidFlushReason, "UNKOWN-" + invalidFlushReason)
+ .put(invalidFlushReason, "UNKNOWN-" + invalidFlushReason)
.build();
expectedMap.forEach(
diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
new file mode 100644
index 0000000..3373b8b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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 android.view.contentcapture;
+
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.contentprotection.ContentProtectionEventProcessor;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test for {@link MainContentCaptureSession}.
+ *
+ * <p>Run with: {@code atest
+ * FrameworksCoreTests:android.view.contentcapture.MainContentCaptureSessionTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MainContentCaptureSessionTest {
+
+ private static final int BUFFER_SIZE = 100;
+
+ private static final int REASON = 123;
+
+ private static final ContentCaptureEvent EVENT =
+ new ContentCaptureEvent(/* sessionId= */ 0, TYPE_SESSION_STARTED);
+
+ private static final ComponentName COMPONENT_NAME =
+ new ComponentName("com.test.package", "TestClass");
+
+ private static final Context sContext = ApplicationProvider.getApplicationContext();
+
+ private static final ContentCaptureManager.StrippedContext sStrippedContext =
+ new ContentCaptureManager.StrippedContext(sContext);
+
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock private IContentCaptureManager mMockSystemServerInterface;
+
+ @Mock private ContentProtectionEventProcessor mMockContentProtectionEventProcessor;
+
+ @Mock private IContentCaptureDirectManager mMockContentCaptureDirectManager;
+
+ @Test
+ public void onSessionStarted_contentProtectionEnabled_processorCreated() {
+ MainContentCaptureSession session = createSession();
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+
+ session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
+
+ assertThat(session.mContentProtectionEventProcessor).isNotNull();
+ }
+
+ @Test
+ public void onSessionStarted_contentProtectionDisabled_processorNotCreated() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ false);
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
+
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ }
+
+ @Test
+ public void onSessionStarted_contentProtectionNoBuffer_processorNotCreated() {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ new ContentCaptureOptions.ContentProtectionOptions(
+ /* enableReceiver= */ true, -BUFFER_SIZE));
+ MainContentCaptureSession session = createSession(options);
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
+
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ }
+
+ @Test
+ public void onSessionStarted_noComponentName_processorNotCreated() {
+ MainContentCaptureSession session = createSession();
+ session.mComponentName = null;
+
+ session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null);
+
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+ }
+
+ @Test
+ public void sendEvent_contentCaptureDisabled_contentProtectionDisabled() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ false,
+ /* enableContentProtectionReceiver= */ false);
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.sendEvent(EVENT);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mEvents).isNull();
+ }
+
+ @Test
+ public void sendEvent_contentCaptureDisabled_contentProtectionEnabled() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ false,
+ /* enableContentProtectionReceiver= */ true);
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.sendEvent(EVENT);
+
+ verify(mMockContentProtectionEventProcessor).processEvent(EVENT);
+ assertThat(session.mEvents).isNull();
+ }
+
+ @Test
+ public void sendEvent_contentCaptureEnabled_contentProtectionDisabled() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ false);
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.sendEvent(EVENT);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mEvents).isNotNull();
+ assertThat(session.mEvents).containsExactly(EVENT);
+ }
+
+ @Test
+ public void sendEvent_contentCaptureEnabled_contentProtectionEnabled() {
+ MainContentCaptureSession session = createSession();
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.sendEvent(EVENT);
+
+ verify(mMockContentProtectionEventProcessor).processEvent(EVENT);
+ assertThat(session.mEvents).isNotNull();
+ assertThat(session.mEvents).containsExactly(EVENT);
+ }
+
+ @Test
+ public void sendEvent_contentProtectionEnabled_processorNotCreated() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ false,
+ /* enableContentProtectionReceiver= */ true);
+
+ session.sendEvent(EVENT);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mEvents).isNull();
+ }
+
+ @Test
+ public void flush_contentCaptureDisabled_contentProtectionDisabled() throws Exception {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ false,
+ /* enableContentProtectionReceiver= */ false);
+ MainContentCaptureSession session = createSession(options);
+ session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.flush(REASON);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ verifyZeroInteractions(mMockContentCaptureDirectManager);
+ assertThat(session.mEvents).containsExactly(EVENT);
+ }
+
+ @Test
+ public void flush_contentCaptureDisabled_contentProtectionEnabled() {
+ MainContentCaptureSession session =
+ createSession(
+ /* enableContentCaptureReceiver= */ false,
+ /* enableContentProtectionReceiver= */ true);
+ session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.flush(REASON);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ verifyZeroInteractions(mMockContentCaptureDirectManager);
+ assertThat(session.mEvents).containsExactly(EVENT);
+ }
+
+ @Test
+ public void flush_contentCaptureEnabled_contentProtectionDisabled() throws Exception {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ false);
+ MainContentCaptureSession session = createSession(options);
+ session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.flush(REASON);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mEvents).isEmpty();
+ assertEventFlushedContentCapture(options);
+ }
+
+ @Test
+ public void flush_contentCaptureEnabled_contentProtectionEnabled() throws Exception {
+ ContentCaptureOptions options =
+ createOptions(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ true);
+ MainContentCaptureSession session = createSession(options);
+ session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
+ session.mDirectServiceInterface = mMockContentCaptureDirectManager;
+
+ session.flush(REASON);
+
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mEvents).isEmpty();
+ assertEventFlushedContentCapture(options);
+ }
+
+ @Test
+ public void destroySession() throws Exception {
+ MainContentCaptureSession session = createSession();
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.destroySession();
+
+ verify(mMockSystemServerInterface).finishSession(anyInt());
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mDirectServiceInterface).isNull();
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+ }
+
+ @Test
+ public void resetSession() {
+ MainContentCaptureSession session = createSession();
+ session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor;
+
+ session.resetSession(/* newState= */ 0);
+
+ verifyZeroInteractions(mMockSystemServerInterface);
+ verifyZeroInteractions(mMockContentProtectionEventProcessor);
+ assertThat(session.mDirectServiceInterface).isNull();
+ assertThat(session.mContentProtectionEventProcessor).isNull();
+ }
+
+ private static ContentCaptureOptions createOptions(
+ boolean enableContentCaptureReceiver,
+ ContentCaptureOptions.ContentProtectionOptions contentProtectionOptions) {
+ return new ContentCaptureOptions(
+ /* loggingLevel= */ 0,
+ BUFFER_SIZE,
+ /* idleFlushingFrequencyMs= */ 0,
+ /* textChangeFlushingFrequencyMs= */ 0,
+ /* logHistorySize= */ 0,
+ /* disableFlushForViewTreeAppearing= */ false,
+ enableContentCaptureReceiver,
+ contentProtectionOptions,
+ /* whitelistedComponents= */ null);
+ }
+
+ private static ContentCaptureOptions createOptions(
+ boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) {
+ return createOptions(
+ enableContentCaptureReceiver,
+ new ContentCaptureOptions.ContentProtectionOptions(
+ enableContentProtectionReceiver, BUFFER_SIZE));
+ }
+
+ private ContentCaptureManager createManager(ContentCaptureOptions options) {
+ return new ContentCaptureManager(sContext, mMockSystemServerInterface, options);
+ }
+
+ private MainContentCaptureSession createSession(ContentCaptureManager manager) {
+ MainContentCaptureSession session =
+ new MainContentCaptureSession(
+ sStrippedContext,
+ manager,
+ new Handler(Looper.getMainLooper()),
+ mMockSystemServerInterface);
+ session.mComponentName = COMPONENT_NAME;
+ return session;
+ }
+
+ private MainContentCaptureSession createSession(ContentCaptureOptions options) {
+ return createSession(createManager(options));
+ }
+
+ private MainContentCaptureSession createSession(
+ boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) {
+ return createSession(
+ createOptions(enableContentCaptureReceiver, enableContentProtectionReceiver));
+ }
+
+ private MainContentCaptureSession createSession() {
+ return createSession(
+ /* enableContentCaptureReceiver= */ true,
+ /* enableContentProtectionReceiver= */ true);
+ }
+
+ private void assertEventFlushedContentCapture(ContentCaptureOptions options) throws Exception {
+ ArgumentCaptor<ParceledListSlice> captor = ArgumentCaptor.forClass(ParceledListSlice.class);
+ verify(mMockContentCaptureDirectManager)
+ .sendEvents(captor.capture(), eq(REASON), eq(options));
+
+ assertThat(captor.getValue()).isNotNull();
+ List<ContentCaptureEvent> actual = captor.getValue().getList();
+ assertThat(actual).isNotNull();
+ assertThat(actual).containsExactly(EVENT);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
index 4adadf1..39a2e0e 100644
--- a/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
+++ b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
@@ -91,6 +91,8 @@
private static final Set<Integer> EVENT_TYPES_TO_STORE =
ImmutableSet.of(TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED);
+ private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;
+
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private RingBuffer<ContentCaptureEvent> mMockEventBuffer;
@@ -232,6 +234,56 @@
}
@Test
+ public void processEvent_loginDetected_belowResetLimit() throws Exception {
+ when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
+ mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
+ ContentCaptureEvent event =
+ createAndroidPasswordFieldEvent(
+ ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS; i++) {
+ mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
+ }
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+
+ mContentProtectionEventProcessor.processEvent(event);
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer).clear();
+ verify(mMockEventBuffer).toArray();
+ assertOnLoginDetected();
+ }
+
+ @Test
+ public void processEvent_loginDetected_aboveResetLimit() throws Exception {
+ mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
+ ContentCaptureEvent event =
+ createAndroidPasswordFieldEvent(
+ ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS + 1; i++) {
+ mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
+ }
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+
+ mContentProtectionEventProcessor.processEvent(event);
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isTrue();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+ }
+
+ @Test
public void processEvent_multipleLoginsDetected_belowFlushThreshold() throws Exception {
when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index e2fb46a..e7b1110 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -16,9 +16,14 @@
package android.view.inputmethod;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assert.assertEquals;
+import android.os.BadParcelableException;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import androidx.test.filters.SmallTest;
@@ -31,6 +36,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
+@Presubmit
public class InputMethodSubtypeArrayTest {
@Test
@@ -59,6 +65,36 @@
assertEquals(clonedArray.get(2), clonedClonedArray.get(2));
}
+ @Test
+ public void testNegativeCount() throws Exception {
+ InputMethodSubtypeArray negativeCountArray;
+ try {
+ // Construct a InputMethodSubtypeArray with: mCount = -1
+ var p = Parcel.obtain();
+ p.writeInt(-1);
+ p.setDataPosition(0);
+ negativeCountArray = new InputMethodSubtypeArray(p);
+ } catch (BadParcelableException e) {
+ // Expected with fix: Prevent negative mCount
+ assertThat(e).hasMessageThat().contains("mCount");
+ return;
+ }
+ assertWithMessage("Test set-up failed")
+ .that(negativeCountArray.getCount()).isEqualTo(-1);
+
+ var p = Parcel.obtain();
+ // Writes: int (mCount), int (mDecompressedSize), byte[] (mCompressedData)
+ negativeCountArray.writeToParcel(p);
+ p.setDataPosition(0);
+ // Reads: int (mCount)
+ // Leaves: int (mDecompressedSize), byte[] (mCompressedData)
+ new InputMethodSubtypeArray(p);
+
+ assertWithMessage("Didn't read all data that was previously written")
+ .that(p.dataPosition())
+ .isEqualTo(p.dataSize());
+ }
+
InputMethodSubtypeArray cloneViaParcel(final InputMethodSubtypeArray original) {
Parcel parcel = null;
try {
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index 6167c4b..1a668f7 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -37,10 +37,23 @@
}
@Test
+ public void testUserRepairMode_isNotRegularUser() {
+ assertTrue(LockPatternUtils.USER_REPAIR_MODE < 0);
+ }
+
+ @Test
public void testUserFrp_isNotAReservedSpecialUser() throws Exception {
assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_ALL, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_FRP);
}
+
+ @Test
+ public void testUserRepairMode_isNotAReservedSpecialUser() throws Exception {
+ assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_ALL, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
+ }
}
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index 29d7902..fde7c08 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -55,7 +55,10 @@
],
platform_apis: true,
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
certificate: "platform",
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 136d1a2..94e23e7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1813,6 +1813,12 @@
"group": "WM_DEBUG_KEEP_SCREEN_ON",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "-479665533": {
+ "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.",
+ "level": "ERROR",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+ },
"-464564167": {
"message": "Current transition prevents automatic focus change",
"level": "VERBOSE",
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 0563519..4a780bc 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -277,6 +277,99 @@
</family>
<alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/>
+ <family name="roboto-flex">
+ <font weight="100" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ <font weight="100" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ </family>
+
<!-- fallback fonts -->
<family lang="und-Arab" variant="elegant">
<font weight="400" style="normal" postScriptName="NotoNaskhArabic">
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 2307d60..b9d3756 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -997,12 +997,63 @@
canvas.concat(m);
canvas.drawBitmap(source, srcR, dstR, paint);
canvas.setBitmap(null);
+
+ // If the source has a gainmap, apply the same set of transformations to the gainmap
+ // and set it on the output
+ if (source.hasGainmap()) {
+ Bitmap newMapContents = transformGainmap(source, m, neww, newh, paint, srcR, dstR,
+ deviceR);
+ if (newMapContents != null) {
+ bitmap.setGainmap(new Gainmap(source.getGainmap(), newMapContents));
+ }
+ }
+
if (isHardware) {
return bitmap.copy(Config.HARDWARE, false);
}
return bitmap;
}
+ private static Bitmap transformGainmap(Bitmap source, Matrix m, int neww, int newh, Paint paint,
+ Rect srcR, RectF dstR, RectF deviceR) {
+ Canvas canvas;
+ Bitmap sourceGainmap = source.getGainmap().getGainmapContents();
+ // Gainmaps can be scaled relative to the base image (eg, 1/4th res)
+ // Preserve that relative scaling between the base & gainmap in the output
+ float scaleX = (sourceGainmap.getWidth() / (float) source.getWidth());
+ float scaleY = (sourceGainmap.getHeight() / (float) source.getHeight());
+ int mapw = Math.round(neww * scaleX);
+ int maph = Math.round(newh * scaleY);
+
+ if (mapw == 0 || maph == 0) {
+ // The gainmap has been scaled away entirely, drop it
+ return null;
+ }
+
+ // Scale the computed `srcR` used for rendering the source bitmap to the destination
+ // to be in gainmap dimensions
+ Rect gSrcR = new Rect((int) (srcR.left * scaleX),
+ (int) (srcR.top * scaleY), (int) (srcR.right * scaleX),
+ (int) (srcR.bottom * scaleY));
+
+ // Note: createBitmap isn't used as that requires a non-null colorspace, however
+ // gainmaps don't have a colorspace. So use `nativeCreate` directly to bypass
+ // that colorspace enforcement requirement (#getColorSpace() allows a null return)
+ Bitmap newMapContents = nativeCreate(null, 0, mapw, mapw, maph,
+ sourceGainmap.getConfig().nativeInt, true, 0);
+ newMapContents.eraseColor(0);
+ canvas = new Canvas(newMapContents);
+ // Scale the translate & matrix to be in gainmap-relative dimensions
+ canvas.scale(scaleX, scaleY);
+ canvas.translate(-deviceR.left, -deviceR.top);
+ canvas.concat(m);
+ canvas.drawBitmap(sourceGainmap, gSrcR, dstR, paint);
+ canvas.setBitmap(null);
+ // Create a new gainmap using a copy of the metadata information from the source but
+ // with the transformed bitmap created above
+ return newMapContents;
+ }
+
/**
* Returns a mutable bitmap with the specified width and height. Its
* initial density is as per {@link #getDensity}. The newly created
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index 9ac84a6..f639521 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -122,6 +122,16 @@
}
/**
+ * Creates a new gainmap using the provided gainmap as the metadata source and the provided
+ * bitmap as the replacement for the gainmapContents
+ * TODO: Make public, it's useful
+ * @hide
+ */
+ public Gainmap(@NonNull Gainmap gainmap, @NonNull Bitmap gainmapContents) {
+ this(gainmapContents, nCreateCopy(gainmap.mNativePtr));
+ }
+
+ /**
* @return Returns the image data of the gainmap represented as a Bitmap. This is represented
* as a Bitmap for broad API compatibility, however certain aspects of the Bitmap are ignored
* such as {@link Bitmap#getColorSpace()} or {@link Bitmap#getGainmap()} as they are not
@@ -325,6 +335,7 @@
private static native long nGetFinalizer();
private static native long nCreateEmpty();
+ private static native long nCreateCopy(long source);
private static native void nSetBitmap(long ptr, Bitmap bitmap);
diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
index 5d77713..ce24275 100644
--- a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
+++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
@@ -13,13 +13,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <group android:translateY="8.0">
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="128dp"
+ android:height="4dp"
+ android:viewportWidth="128"
+ android:viewportHeight="4"
+ >
+ <group>
+ <clip-path
+ android:pathData="M2 0H126C127.105 0 128 0.895431 128 2C128 3.10457 127.105 4 126 4H2C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0Z"
+ />
<path
- android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/>
+ android:pathData="M0 0V4H128V0"
+ android:fillColor="@android:color/black"
+ />
</group>
</vector>
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 1d6864c..0ca912e 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
@@ -28,6 +28,7 @@
android:layout_width="176dp"
android:layout_height="42dp"
android:paddingHorizontal="24dp"
+ android:paddingVertical="19dp"
android:contentDescription="@string/handle_text"
android:src="@drawable/decor_handle_dark"
tools:tint="@color/desktop_mode_caption_handle_bar_dark"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 2141259..2e3f604 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -416,7 +416,7 @@
<!-- The radius of the caption menu shadow. -->
<dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen>
- <dimen name="freeform_resize_handle">30dp</dimen>
+ <dimen name="freeform_resize_handle">15dp</dimen>
<dimen name="freeform_resize_corner">44dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 8635c56..d902fd4 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -93,62 +93,34 @@
<style name="RestartDialogTitleText">
<item name="android:textSize">24sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textAppearance">
- @*android:style/TextAppearance.DeviceDefault.Headline
- </item>
- <item name="android:fontFamily">
- @*android:string/config_bodyFontFamilyMedium
- </item>
+ <item name="android:lineSpacingExtra">8sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
- <style name="RestartDialogBodyText">
+ <style name="RestartDialogBodyStyle">
<item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ </style>
+
+ <style name="RestartDialogBodyText" parent="RestartDialogBodyStyle">
<item name="android:letterSpacing">0.02</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
- <item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textAppearance">
- @*android:style/TextAppearance.DeviceDefault.Body2
- </item>
- <item name="android:fontFamily">
- @*android:string/config_bodyFontFamily
- </item>
+ <item name="android:lineSpacingExtra">6sp</item>
</style>
- <style name="RestartDialogCheckboxText">
- <item name="android:textSize">16sp</item>
+ <style name="RestartDialogCheckboxText" parent="RestartDialogBodyStyle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:lineSpacingExtra">4sp</item>
- <item name="android:textAppearance">
- @*android:style/TextAppearance.DeviceDefault.Headline
- </item>
- <item name="android:fontFamily">
- @*android:string/config_bodyFontFamilyMedium
- </item>
+ <item name="android:lineSpacingExtra">6sp</item>
</style>
- <style name="RestartDialogDismissButton">
+ <style name="RestartDialogDismissButton" parent="RestartDialogBodyStyle">
<item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textAppearance">
- @*android:style/TextAppearance.DeviceDefault.Body2
- </item>
- <item name="android:fontFamily">
- @*android:string/config_bodyFontFamily
- </item>
</style>
- <style name="RestartDialogConfirmButton">
+ <style name="RestartDialogConfirmButton" parent="RestartDialogBodyStyle">
<item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
- <item name="android:textAppearance">
- @*android:style/TextAppearance.DeviceDefault.Body2
- </item>
- <item name="android:fontFamily">
- @*android:string/config_bodyFontFamily
- </item>
</style>
<style name="ReachabilityEduHandLayout" parent="Theme.AppCompat.Light">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index 7b37d59..57d374b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -20,6 +20,8 @@
import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
+import static com.android.wm.shell.transition.DefaultTransitionHandler.isSupportedOverrideAnimation;
+
import static java.util.Objects.requireNonNull;
import android.content.Context;
@@ -113,8 +115,11 @@
return false;
}
final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
- if (options != null && options.getType() == ANIM_SCENE_TRANSITION) {
- // Scene-transition will be handled by app side.
+ if (options != null
+ // Scene-transition will be handled by app side.
+ && (options.getType() == ANIM_SCENE_TRANSITION
+ // Use default transition handler to animate override animation.
+ || isSupportedOverrideAnimation(options))) {
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 9fcd207..e1a3f3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -55,6 +55,7 @@
import android.util.IntProperty;
import android.util.Log;
import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -459,7 +460,9 @@
if (mManageButton != null) {
int visibility = mManageButton.getVisibility();
removeView(mManageButton);
- mManageButton = (AlphaOptimizedButton) LayoutInflater.from(getContext()).inflate(
+ ContextThemeWrapper ctw = new ContextThemeWrapper(getContext(),
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ mManageButton = (AlphaOptimizedButton) LayoutInflater.from(ctw).inflate(
R.layout.bubble_manage_button, this /* parent */, false /* attach */);
addView(mManageButton);
mManageButton.setVisibility(visibility);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 3a46797..80e2999 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -104,7 +104,11 @@
@Override
protected BubbleViewInfo doInBackground(Void... voids) {
- if (mController.get().isShowingAsBubbleBar()) {
+ if (!verifyState()) {
+ // If we're in an inconsistent state, then switched modes and should just bail now.
+ return null;
+ }
+ if (mLayerView.get() != null) {
return BubbleViewInfo.populateForBubbleBar(mContext.get(), mController.get(),
mLayerView.get(), mIconFactory, mBubble, mSkipInflation);
} else {
@@ -118,7 +122,11 @@
if (isCancelled() || viewInfo == null) {
return;
}
+
mMainExecutor.execute(() -> {
+ if (!verifyState()) {
+ return;
+ }
mBubble.setViewInfo(viewInfo);
if (mCallback != null) {
mCallback.onBubbleViewsReady(mBubble);
@@ -126,6 +134,14 @@
});
}
+ private boolean verifyState() {
+ if (mController.get().isShowingAsBubbleBar()) {
+ return mLayerView.get() != null;
+ } else {
+ return mStackView.get() != null;
+ }
+ }
+
/**
* Info necessary to render a bubble.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index ae1f433..72702e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -79,7 +79,7 @@
}
/** Query all listeners for changes that should happen on display change. */
- public void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
+ void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) {
for (OnDisplayChangingListener c : mDisplayChangeListener) {
c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index f07ea75..8353900 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -29,6 +29,7 @@
import android.view.IDisplayWindowListener;
import android.view.IWindowManager;
import android.view.InsetsState;
+import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
@@ -85,11 +86,6 @@
}
}
- /** Get the DisplayChangeController. */
- public DisplayChangeController getChangeController() {
- return mChangeController;
- }
-
/**
* Gets a display by id from DisplayManager.
*/
@@ -195,6 +191,26 @@
}
}
+
+ /** Called when a display rotate requested. */
+ public void onDisplayRotateRequested(WindowContainerTransaction wct, int displayId,
+ int fromRotation, int toRotation) {
+ synchronized (mDisplays) {
+ final DisplayRecord dr = mDisplays.get(displayId);
+ if (dr == null) {
+ Slog.w(TAG, "Skipping Display rotate on non-added display.");
+ return;
+ }
+
+ if (dr.mDisplayLayout != null) {
+ dr.mDisplayLayout.rotateTo(dr.mContext.getResources(), toRotation);
+ }
+
+ mChangeController.dispatchOnDisplayChange(
+ wct, displayId, fromRotation, toRotation, null /* newDisplayAreaInfo */);
+ }
+ }
+
private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
synchronized (mDisplays) {
final DisplayRecord dr = mDisplays.get(displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index d6e1a82..1959eb0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -300,9 +300,12 @@
return mAllowSeamlessRotationDespiteNavBarMoving;
}
- /** @return whether the navigation bar will change sides during rotation. */
+ /**
+ * Returns {@code true} if the navigation bar will change sides during rotation and the display
+ * is not square.
+ */
public boolean navigationBarCanMove() {
- return mNavigationBarCanMove;
+ return mNavigationBarCanMove && mWidth != mHeight;
}
/** @return the rotation that would make the physical display "upside down". */
@@ -375,16 +378,15 @@
insetsState.getDisplayFrame(),
WindowInsets.Type.navigationBars(),
false /* ignoreVisibility */);
- outInsets.set(insets.left, insets.top, insets.right, insets.bottom);
int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
int navBarSize =
getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
if (position == NAV_BAR_BOTTOM) {
- outInsets.bottom = Math.max(outInsets.bottom , navBarSize);
+ outInsets.bottom = Math.max(insets.bottom , navBarSize);
} else if (position == NAV_BAR_RIGHT) {
- outInsets.right = Math.max(outInsets.right , navBarSize);
+ outInsets.right = Math.max(insets.right , navBarSize);
} else if (position == NAV_BAR_LEFT) {
- outInsets.left = Math.max(outInsets.left , navBarSize);
+ outInsets.left = Math.max(insets.left , navBarSize);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index ab8e7e6..f70d3ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -63,8 +63,10 @@
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.InteractionJankMonitorUtils;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
@@ -104,6 +106,7 @@
private final Rect mWinBounds2 = new Rect();
private final SplitLayoutHandler mSplitLayoutHandler;
private final SplitWindowManager mSplitWindowManager;
+ private final DisplayController mDisplayController;
private final DisplayImeController mDisplayImeController;
private final ImePositionProcessor mImePositionProcessor;
private final ResizingEffectPolicy mSurfaceEffectPolicy;
@@ -128,13 +131,14 @@
public SplitLayout(String windowName, Context context, Configuration configuration,
SplitLayoutHandler splitLayoutHandler,
SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
- DisplayImeController displayImeController, ShellTaskOrganizer taskOrganizer,
- int parallaxType) {
+ DisplayController displayController, DisplayImeController displayImeController,
+ ShellTaskOrganizer taskOrganizer, int parallaxType) {
mContext = context.createConfigurationContext(configuration);
mOrientation = configuration.orientation;
mRotation = configuration.windowConfiguration.getRotation();
mDensity = configuration.densityDpi;
mSplitLayoutHandler = splitLayoutHandler;
+ mDisplayController = displayController;
mDisplayImeController = displayImeController;
mSplitWindowManager = new SplitWindowManager(windowName, mContext, configuration,
parentContainerCallbacks);
@@ -145,7 +149,7 @@
updateDividerConfig(mContext);
mRootBounds.set(configuration.windowConfiguration.getBounds());
- mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
resetDividerPosition();
mDimNonImeSide = mContext.getResources().getBoolean(R.bool.config_dimNonImeAttachedSide);
@@ -314,7 +318,7 @@
mRotation = rotation;
mDensity = density;
mUiMode = uiMode;
- mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
updateDividerConfig(mContext);
initDividerPosition(mTempRect);
updateInvisibleRect();
@@ -324,7 +328,7 @@
/** Rotate the layout to specific rotation and calculate new bounds. The stable insets value
* should be calculated by display layout. */
- public void rotateTo(int newRotation, Rect stableInsets) {
+ public void rotateTo(int newRotation) {
final int rotationDelta = (newRotation - mRotation + 4) % 4;
final boolean changeOrient = (rotationDelta % 2) != 0;
@@ -337,7 +341,7 @@
// We only need new bounds here, other configuration should be update later.
mTempRect.set(mRootBounds);
mRootBounds.set(tmpRect);
- mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, stableInsets);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
initDividerPosition(mTempRect);
}
@@ -548,10 +552,9 @@
return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity, hardDismiss);
}
- private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds,
- @Nullable Rect stableInsets) {
+ private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds) {
final boolean isLandscape = isLandscape(rootBounds);
- final Rect insets = stableInsets != null ? stableInsets : getDisplayInsets(context);
+ final Rect insets = getDisplayStableInsets(context);
// Make split axis insets value same as the larger one to avoid bounds1 and bounds2
// have difference for avoiding size-compat mode when switching unresizable apps in
@@ -634,7 +637,7 @@
public void splitSwitching(SurfaceControl.Transaction t, SurfaceControl leash1,
SurfaceControl leash2, Consumer<Rect> finishCallback) {
final boolean isLandscape = isLandscape();
- final Rect insets = getDisplayInsets(mContext);
+ final Rect insets = getDisplayStableInsets(mContext);
insets.set(isLandscape ? insets.left : 0, isLandscape ? 0 : insets.top,
isLandscape ? insets.right : 0, isLandscape ? 0 : insets.bottom);
@@ -705,13 +708,17 @@
return animator;
}
- private static Rect getDisplayInsets(Context context) {
- return context.getSystemService(WindowManager.class)
- .getMaximumWindowMetrics()
- .getWindowInsets()
- .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()
- | WindowInsets.Type.displayCutout())
- .toRect();
+ private Rect getDisplayStableInsets(Context context) {
+ final DisplayLayout displayLayout =
+ mDisplayController.getDisplayLayout(context.getDisplayId());
+ return displayLayout != null
+ ? displayLayout.stableInsets()
+ : context.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics()
+ .getWindowInsets()
+ .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()
+ | WindowInsets.Type.displayCutout())
+ .toRect();
}
private static boolean isLandscape(Rect bounds) {
@@ -784,7 +791,7 @@
private int getSmallestWidthDp(Rect bounds) {
mTempRect.set(bounds);
- mTempRect.inset(getDisplayInsets(mContext));
+ mTempRect.inset(getDisplayStableInsets(mContext));
final int minWidth = Math.min(mTempRect.width(), mTempRect.height());
final float density = mContext.getResources().getDisplayMetrics().density;
return (int) (minWidth / density);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 7cc2b9e..34a6e0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -103,13 +103,13 @@
import com.android.wm.shell.unfold.UnfoldTransitionHandler;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+import java.util.Optional;
+
import dagger.BindsOptionalOf;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
-import java.util.Optional;
-
/**
* Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
* accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -556,13 +556,15 @@
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellAnimationThread ShellExecutor animExecutor,
- ShellCommandHandler shellCommandHandler) {
+ ShellCommandHandler shellCommandHandler,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
if (!context.getResources().getBoolean(R.bool.config_registerShellTransitionsOnInit)) {
// TODO(b/238217847): Force override shell init if registration is disabled
shellInit = new ShellInit(mainExecutor);
}
return new Transitions(context, shellInit, shellController, organizer, pool,
- displayController, mainExecutor, mainHandler, animExecutor, shellCommandHandler);
+ displayController, mainExecutor, mainHandler, animExecutor, shellCommandHandler,
+ rootTaskDisplayAreaOrganizer);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index e2010c2..ec40244 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -57,6 +57,7 @@
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
+import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -205,8 +206,7 @@
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController) {
+ Optional<DesktopTasksController> desktopTasksController) {
if (DesktopModeStatus.isAnyEnabled()) {
return new DesktopModeWindowDecorViewModel(
context,
@@ -217,8 +217,7 @@
syncQueue,
transitions,
desktopModeController,
- desktopTasksController,
- splitScreenController);
+ desktopTasksController);
}
return new CaptionWindowDecorViewModel(
context,
@@ -336,11 +335,13 @@
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel,
@ShellMainThread ShellExecutor mainExecutor) {
return new SplitScreenController(context, shellInit, shellCommandHandler, shellController,
shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController,
displayImeController, displayInsetsController, dragAndDropController, transitions,
- transactionPool, iconProvider, recentTasks, launchAdjacentController, mainExecutor);
+ transactionPool, iconProvider, recentTasks, launchAdjacentController,
+ windowDecorViewModel, mainExecutor);
}
//
@@ -690,6 +691,7 @@
Transitions transitions,
EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler,
ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler,
+ ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
LaunchAdjacentController launchAdjacentController,
@ShellMainThread ShellExecutor mainExecutor
@@ -697,7 +699,8 @@
return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,
- desktopModeTaskRepository, launchAdjacentController, mainExecutor);
+ toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository,
+ launchAdjacentController, mainExecutor);
}
@WMSingleton
@@ -709,6 +712,13 @@
@WMSingleton
@Provides
+ static ToggleResizeDesktopTaskTransitionHandler provideToggleResizeDesktopTaskTransitionHandler(
+ Transitions transitions) {
+ return new ToggleResizeDesktopTaskTransitionHandler(transitions);
+ }
+
+ @WMSingleton
+ @Provides
static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler(
Transitions transitions,
Context context
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index a490fb8..711df0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -87,8 +87,10 @@
visibleTasksListeners[visibleTasksListener] = executor
displayData.keyIterator().forEach { displayId ->
val visibleTasks = getVisibleTaskCount(displayId)
+ val stashed = isStashed(displayId)
executor.execute {
visibleTasksListener.onVisibilityChanged(displayId, visibleTasks > 0)
+ visibleTasksListener.onStashedChanged(displayId, stashed)
}
}
}
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 821fc13..d016e73c 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
@@ -31,6 +31,7 @@
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
+import android.util.DisplayMetrics.DENSITY_DEFAULT
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -38,7 +39,6 @@
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
-import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.annotation.BinderThread
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -79,6 +79,8 @@
private val transitions: Transitions,
private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler,
private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler,
+ private val toggleResizeDesktopTaskTransitionHandler:
+ ToggleResizeDesktopTaskTransitionHandler,
private val desktopModeTaskRepository: DesktopModeTaskRepository,
private val launchAdjacentController: LaunchAdjacentController,
@ShellMainThread private val mainExecutor: ShellExecutor
@@ -164,21 +166,28 @@
}
/** Move a task with given `taskId` to desktop */
- fun moveToDesktop(taskId: Int) {
- shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task) }
+ fun moveToDesktop(taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction()) {
+ shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
+ task -> moveToDesktop(task, wct)
+ }
}
- /** Move a task to desktop */
- fun moveToDesktop(task: RunningTaskInfo) {
+ /**
+ * Move a task to desktop
+ */
+ fun moveToDesktop(
+ task: RunningTaskInfo,
+ wct: WindowContainerTransaction = WindowContainerTransaction()
+ ) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: moveToDesktop taskId=%d",
task.taskId
)
- val wct = WindowContainerTransaction()
// Bring other apps to front first
bringDesktopAppsToFront(task.displayId, wct)
- addMoveToDesktopChanges(wct, task.token)
+ addMoveToDesktopChanges(wct, task)
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
} else {
@@ -198,7 +207,7 @@
)
val wct = WindowContainerTransaction()
moveHomeTaskToFront(wct)
- addMoveToDesktopChanges(wct, taskInfo.getToken())
+ addMoveToDesktopChanges(wct, taskInfo)
wct.setBounds(taskInfo.token, startBounds)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -218,7 +227,7 @@
)
val wct = WindowContainerTransaction()
bringDesktopAppsToFront(taskInfo.displayId, wct)
- addMoveToDesktopChanges(wct, taskInfo.getToken())
+ addMoveToDesktopChanges(wct, taskInfo)
wct.setBounds(taskInfo.token, freeformBounds)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -244,7 +253,7 @@
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
} else {
@@ -263,7 +272,7 @@
task.taskId
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, position,
mOnAnimationFinishedCallback)
@@ -280,7 +289,7 @@
task.taskId
)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
@@ -376,6 +385,49 @@
}
}
+ /** Quick-resizes a desktop task, toggling between the stable bounds and the default bounds. */
+ fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo, windowDecor: DesktopModeWindowDecoration) {
+ val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
+
+ val stableBounds = Rect()
+ displayLayout.getStableBounds(stableBounds)
+ val destinationBounds = Rect()
+ if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
+ // The desktop task is currently occupying the whole stable bounds, toggle to the
+ // default bounds.
+ getDefaultDesktopTaskBounds(
+ density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT,
+ stableBounds = stableBounds,
+ outBounds = destinationBounds
+ )
+ } else {
+ // Toggle to the stable bounds.
+ destinationBounds.set(stableBounds)
+ }
+
+ val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ toggleResizeDesktopTaskTransitionHandler.startTransition(
+ wct,
+ taskInfo.taskId,
+ windowDecor
+ )
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
+ private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {
+ val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()
+ val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt()
+ outBounds.set(0, 0, width, height)
+ // Center the task in stable bounds
+ outBounds.offset(
+ stableBounds.centerX() - outBounds.centerX(),
+ stableBounds.centerY() - outBounds.centerY()
+ )
+ }
+
/**
* Get windowing move for a given `taskId`
*
@@ -509,7 +561,7 @@
task.taskId
)
return WindowContainerTransaction().also { wct ->
- addMoveToFullscreenChanges(wct, task.token)
+ addMoveToFullscreenChanges(wct, task)
}
}
return null
@@ -525,7 +577,7 @@
task.taskId
)
return WindowContainerTransaction().also { wct ->
- addMoveToDesktopChanges(wct, task.token)
+ addMoveToDesktopChanges(wct, task)
}
}
return null
@@ -539,30 +591,44 @@
)
val wct = WindowContainerTransaction()
bringDesktopAppsToFront(task.displayId, wct)
- addMoveToDesktopChanges(wct, task.token)
+ addMoveToDesktopChanges(wct, task)
desktopModeTaskRepository.setStashed(task.displayId, false)
return wct
}
private fun addMoveToDesktopChanges(
wct: WindowContainerTransaction,
- token: WindowContainerToken
+ taskInfo: RunningTaskInfo
) {
- wct.setWindowingMode(token, WINDOWING_MODE_FREEFORM)
- wct.reorder(token, true /* onTop */)
+ val displayWindowingMode = taskInfo.configuration.windowConfiguration.displayWindowingMode
+ val targetWindowingMode = if (displayWindowingMode == WINDOWING_MODE_FREEFORM) {
+ // Display windowing is freeform, set to undefined and inherit it
+ WINDOWING_MODE_UNDEFINED
+ } else {
+ WINDOWING_MODE_FREEFORM
+ }
+ wct.setWindowingMode(taskInfo.token, targetWindowingMode)
+ wct.reorder(taskInfo.token, true /* onTop */)
if (isDesktopDensityOverrideSet()) {
- wct.setDensityDpi(token, getDesktopDensityDpi())
+ wct.setDensityDpi(taskInfo.token, getDesktopDensityDpi())
}
}
private fun addMoveToFullscreenChanges(
wct: WindowContainerTransaction,
- token: WindowContainerToken
+ taskInfo: RunningTaskInfo
) {
- wct.setWindowingMode(token, WINDOWING_MODE_FULLSCREEN)
- wct.setBounds(token, null)
+ val displayWindowingMode = taskInfo.configuration.windowConfiguration.displayWindowingMode
+ val targetWindowingMode = if (displayWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // Display windowing is fullscreen, set to undefined and inherit it
+ WINDOWING_MODE_UNDEFINED
+ } else {
+ WINDOWING_MODE_FULLSCREEN
+ }
+ wct.setWindowingMode(taskInfo.token, targetWindowingMode)
+ wct.setBounds(taskInfo.token, null)
if (isDesktopDensityOverrideSet()) {
- wct.setDensityDpi(token, getFullscreenDensityDpi())
+ wct.setDensityDpi(taskInfo.token, getFullscreenDensityDpi())
}
}
@@ -764,16 +830,21 @@
private val listener: VisibleTasksListener = object : VisibleTasksListener {
override fun onVisibilityChanged(displayId: Int, visible: Boolean) {
- // TODO(b/261234402): move visibility from sysui state to listener
+ KtProtoLog.v(
+ WM_SHELL_DESKTOP_MODE,
+ "IDesktopModeImpl: onVisibilityChanged display=%d visible=%b",
+ displayId,
+ visible
+ )
remoteListener.call { l -> l.onVisibilityChanged(displayId, visible) }
}
override fun onStashedChanged(displayId: Int, stashed: Boolean) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
- "IDesktopModeImpl: onStashedChanged stashed=%b display=%d",
- stashed,
- displayId
+ "IDesktopModeImpl: onStashedChanged display=%d stashed=%b",
+ displayId,
+ stashed
)
remoteListener.call { l -> l.onStashedChanged(displayId, stashed) }
}
@@ -858,6 +929,14 @@
SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0)
private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
+ // Override default freeform task width when desktop mode is enabled. In dips.
+ private val DESKTOP_MODE_DEFAULT_WIDTH_DP =
+ SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840)
+
+ // Override default freeform task height when desktop mode is enabled. In dips.
+ private val DESKTOP_MODE_DEFAULT_HEIGHT_DP =
+ SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630)
+
/**
* Check if desktop density override is enabled
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
new file mode 100644
index 0000000..94788e4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.wm.shell.desktopmode
+
+import android.animation.Animator
+import android.animation.RectEvaluator
+import android.animation.ValueAnimator
+import android.graphics.Rect
+import android.os.IBinder
+import android.util.SparseArray
+import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import androidx.core.animation.addListener
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
+import java.util.function.Supplier
+
+/** Handles the animation of quick resizing of desktop tasks. */
+class ToggleResizeDesktopTaskTransitionHandler(
+ private val transitions: Transitions,
+ private val transactionSupplier: Supplier<SurfaceControl.Transaction>
+) : Transitions.TransitionHandler {
+
+ private val rectEvaluator = RectEvaluator(Rect())
+ private val taskToDecorationMap = SparseArray<DesktopModeWindowDecoration>()
+
+ private var boundsAnimator: Animator? = null
+
+ constructor(
+ transitions: Transitions
+ ) : this(transitions, Supplier { SurfaceControl.Transaction() })
+
+ /** Starts a quick resize transition. */
+ fun startTransition(
+ wct: WindowContainerTransaction,
+ taskId: Int,
+ windowDecoration: DesktopModeWindowDecoration
+ ) {
+ // Pause relayout until the transition animation finishes.
+ windowDecoration.incrementRelayoutBlock()
+ transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this)
+ taskToDecorationMap.put(taskId, windowDecoration)
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: Transitions.TransitionFinishCallback
+ ): Boolean {
+ val change = findRelevantChange(info)
+ val leash = change.leash
+ val taskId = change.taskInfo.taskId
+ val startBounds = change.startAbsBounds
+ val endBounds = change.endAbsBounds
+ val windowDecor =
+ taskToDecorationMap.removeReturnOld(taskId)
+ ?: throw IllegalStateException("Window decoration not found for task $taskId")
+
+ val tx = transactionSupplier.get()
+ boundsAnimator?.cancel()
+ boundsAnimator =
+ ValueAnimator.ofObject(rectEvaluator, startBounds, endBounds)
+ .setDuration(RESIZE_DURATION_MS)
+ .apply {
+ addListener(
+ onStart = {
+ startTransaction
+ .setPosition(
+ leash,
+ startBounds.left.toFloat(),
+ startBounds.top.toFloat()
+ )
+ .setWindowCrop(leash, startBounds.width(), startBounds.height())
+ .show(leash)
+ windowDecor.showResizeVeil(startTransaction, startBounds)
+ },
+ onEnd = {
+ finishTransaction
+ .setPosition(
+ leash,
+ endBounds.left.toFloat(),
+ endBounds.top.toFloat()
+ )
+ .setWindowCrop(leash, endBounds.width(), endBounds.height())
+ .show(leash)
+ windowDecor.hideResizeVeil()
+ finishCallback.onTransitionFinished(null, null)
+ boundsAnimator = null
+ }
+ )
+ addUpdateListener { anim ->
+ val rect = anim.animatedValue as Rect
+ tx.setPosition(leash, rect.left.toFloat(), rect.top.toFloat())
+ .setWindowCrop(leash, rect.width(), rect.height())
+ .show(leash)
+ windowDecor.updateResizeVeil(tx, rect)
+ }
+ start()
+ }
+ return true
+ }
+
+ override fun handleRequest(
+ transition: IBinder,
+ request: TransitionRequestInfo
+ ): WindowContainerTransaction? {
+ return null
+ }
+
+ private fun findRelevantChange(info: TransitionInfo): TransitionInfo.Change {
+ val matchingChanges =
+ info.changes.filter { c ->
+ !isWallpaper(c) && isValidTaskChange(c) && c.mode == TRANSIT_CHANGE
+ }
+ if (matchingChanges.size != 1) {
+ throw IllegalStateException(
+ "Expected 1 relevant change but found: ${matchingChanges.size}"
+ )
+ }
+ return matchingChanges.first()
+ }
+
+ private fun isWallpaper(change: TransitionInfo.Change): Boolean {
+ return (change.flags and TransitionInfo.FLAG_IS_WALLPAPER) != 0
+ }
+
+ private fun isValidTaskChange(change: TransitionInfo.Change): Boolean {
+ return change.taskInfo != null && change.taskInfo?.taskId != -1
+ }
+
+ companion object {
+ private const val RESIZE_DURATION_MS = 300L
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
index c795a05..f9ea1d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -21,8 +21,8 @@
building to check the log state (is enabled) before printing the print format style log.
**Notes**
-- ProtoLogs currently only work from soong builds (ie. via make/mp). We need to reimplement the
- tool for use with SysUI-studio
+- ProtoLogs are only fully supported from soong builds (ie. via make/mp). In SysUI-studio it falls
+ back to log via Logcat
- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
traces in Winscope)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index db7c3fc..07d11cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -438,6 +438,8 @@
*/
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "startSwipePipToHome: %s, state=%s", componentName, mPipTransitionState);
mPipTransitionState.setInSwipePipToHomeTransition(true);
sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP);
setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
@@ -450,6 +452,8 @@
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "stopSwipePipToHome: %s, state=%s", componentName, mPipTransitionState);
// do nothing if there is no startSwipePipToHome being called before
if (!mPipTransitionState.getInSwipePipToHomeTransition()) {
return;
@@ -522,23 +526,14 @@
return;
}
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "exitPip: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (isLaunchIntoPipTask()) {
exitLaunchIntoPipTask(wct);
return;
}
- if (ENABLE_SHELL_TRANSITIONS) {
- if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
- mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
- isPipTopLeft()
- ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
- mPipTransitionController.startExitTransition(
- TRANSIT_EXIT_PIP_TO_SPLIT, wct, null /* destinationBounds */);
- return;
- }
- }
-
final Rect displayBounds = mPipBoundsState.getDisplayBounds();
final Rect destinationBounds = new Rect(displayBounds);
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
@@ -547,10 +542,8 @@
// For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
// until the animation is finished. Otherwise if the activity is resumed and focused at the
// begin of aniamtion, the app may do something too early to distub the animation.
- final boolean toFullscreen = destinationBounds.equals(displayBounds);
- if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
- && !toFullscreen)) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
// When exit to fullscreen with Shell transition enabled, we update the Task windowing
// mode directly so that it can also trigger display rotation and visibility update in
// the same transition if there will be any.
@@ -559,6 +552,8 @@
// destinationBounds calculated above will be incorrect if this is with rotation.
wct.setBounds(mToken, null);
} else {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "exitPip: %s, dest=%s", mTaskInfo.topActivity, destinationBounds);
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
@@ -580,9 +575,29 @@
mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
+ wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
+ isPipToTopLeft()
+ ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ mPipTransitionController.startExitTransition(
+ TRANSIT_EXIT_PIP_TO_SPLIT, wct, destinationBounds);
+ return;
+ }
+
+ if (mSplitScreenOptional.isPresent()) {
+ // If pip activity will reparent to origin task case and if the origin task still
+ // under split root, apply exit split transaction to make it expand to fullscreen.
+ SplitScreenController split = mSplitScreenOptional.get();
+ if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
+ split.prepareExitSplitScreen(wct, split.getStageOfTask(
+ mTaskInfo.lastParentTaskIdBeforePip));
+ }
+ }
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
return;
}
+
if (mSplitScreenOptional.isPresent()) {
// If pip activity will reparent to origin task case and if the origin task still under
// split root, just exit split screen here to ensure it could expand to fullscreen.
@@ -656,9 +671,13 @@
animator.setInterpolator(Interpolators.ALPHA_OUT);
animator.start();
mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "removePip: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
}
private void removePipImmediately() {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "removePipImmediately: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setBounds(mToken, null);
@@ -723,6 +742,8 @@
}
mPipUiEventLoggerLogger.log(uiEventEnum);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onTaskAppeared: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
@@ -774,6 +795,9 @@
}
private void onTaskAppearedWithFixedRotation(int animationType) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onTaskAppearedWithFixedRotation: %s, state=%s animationType=%d",
+ mTaskInfo.topActivity, mPipTransitionState, animationType);
if (animationType == ANIM_TYPE_ALPHA) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Defer entering PiP alpha animation, fixed rotation is ongoing", TAG);
@@ -920,6 +944,8 @@
*/
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onTaskVanished: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
return;
}
@@ -961,6 +987,9 @@
mPipBoundsState.setOverrideMinSize(
mPipBoundsAlgorithm.getMinimalSize(info.topActivityInfo));
final PictureInPictureParams newParams = info.pictureInPictureParams;
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onTaskInfoChanged: %s, state=%s oldParams=%s newParams=%s",
+ mTaskInfo.topActivity, mPipTransitionState, mPictureInPictureParams, newParams);
// mPictureInPictureParams is only null if there is no PiP
if (newParams == null || mPictureInPictureParams == null) {
@@ -1001,6 +1030,8 @@
@Override
public void onFixedRotationStarted(int displayId, int newRotation) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onFixedRotationStarted: %s, state=%s", mTaskInfo, mPipTransitionState);
mNextRotation = newRotation;
mWaitForFixedRotation = true;
@@ -1022,6 +1053,8 @@
@Override
public void onFixedRotationFinished(int displayId) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onFixedRotationFinished: %s, state=%s", mTaskInfo, mPipTransitionState);
if (!mWaitForFixedRotation) {
return;
}
@@ -1057,6 +1090,9 @@
/** Called when exiting PIP transition is finished to do the state cleanup. */
void onExitPipFinished(TaskInfo info) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onExitPipFinished: %s, state=%s leash=%s",
+ info.topActivity, mPipTransitionState, mLeash);
if (mLeash == null) {
// TODO(239461594): Remove once the double call to onExitPipFinished() is fixed
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -1108,6 +1144,9 @@
/** Explicitly set the visibility of PiP window. */
public void setPipVisibility(boolean visible) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "setPipVisibility: %s, state=%s visible=%s",
+ mTaskInfo.topActivity, mPipTransitionState, visible);
if (!isInPip()) {
return;
}
@@ -1634,17 +1673,6 @@
}
}
- private boolean isPipTopLeft() {
- if (!mSplitScreenOptional.isPresent()) {
- return false;
- }
- final Rect topLeft = new Rect();
- final Rect bottomRight = new Rect();
- mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
-
- return topLeft.contains(mPipBoundsState.getBounds());
- }
-
private boolean isPipToTopLeft() {
if (!mSplitScreenOptional.isPresent()) {
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f9d615a..86b0f33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -308,8 +308,9 @@
@Override
public void end() {
Animator animator = mPipAnimationController.getCurrentAnimator();
- if (animator == null) return;
- animator.end();
+ if (animator != null && animator.isRunning()) {
+ animator.end();
+ }
}
@Override
@@ -815,6 +816,12 @@
final ActivityManager.RunningTaskInfo taskInfo = pipChange.getTaskInfo();
final SurfaceControl leash = pipChange.getLeash();
final int startRotation = pipChange.getStartRotation();
+ // Check again in case some callers use startEnterAnimation directly so the flag was not
+ // set in startAnimation, e.g. from DefaultMixedHandler.
+ if (!mInFixedRotation) {
+ mEndFixedRotation = pipChange.getEndFixedRotation();
+ mInFixedRotation = mEndFixedRotation != ROTATION_UNDEFINED;
+ }
final int endRotation = mInFixedRotation ? mEndFixedRotation : pipChange.getEndRotation();
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
@@ -843,7 +850,7 @@
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
handleSwipePipToHomeTransition(startTransaction, finishTransaction, leash,
- sourceHintRect, destinationBounds, rotationDelta, taskInfo);
+ sourceHintRect, destinationBounds, taskInfo);
return;
}
@@ -934,8 +941,15 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull SurfaceControl leash, @Nullable Rect sourceHintRect,
- @NonNull Rect destinationBounds, int rotationDelta,
+ @NonNull Rect destinationBounds,
@NonNull ActivityManager.RunningTaskInfo pipTaskInfo) {
+ if (mInFixedRotation) {
+ // If rotation changes when returning to home, the transition should contain both the
+ // entering PiP and the display change (PipController#startSwipePipToHome has updated
+ // the display layout to new rotation). So it is not expected to see fixed rotation.
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "%s: SwipePipToHome should not use fixed rotation %d", TAG, mEndFixedRotation);
+ }
final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
@@ -946,12 +960,7 @@
mPipOrganizer.mSwipePipToHomeOverlay = null;
}
- Rect sourceBounds = pipTaskInfo.configuration.windowConfiguration.getBounds();
- if (!Transitions.SHELL_TRANSITIONS_ROTATION && rotationDelta % 2 == 1) {
- // PipController#startSwipePipToHome has updated the display layout to new rotation,
- // so flip the source bounds to match the same orientation.
- sourceBounds = new Rect(0, 0, sourceBounds.height(), sourceBounds.width());
- }
+ final Rect sourceBounds = pipTaskInfo.configuration.windowConfiguration.getBounds();
final PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getAnimator(pipTaskInfo, leash, sourceBounds, sourceBounds,
destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
@@ -980,12 +989,7 @@
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TaskInfo taskInfo) {
- final int changeSize = info.getChanges().size();
- if (changeSize < 4) {
- throw new RuntimeException(
- "Got an exit-pip-to-split transition with unexpected change-list");
- }
- for (int i = changeSize - 1; i >= 0; i--) {
+ for (int i = info.getChanges().size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = info.getChanges().get(i);
final int mode = change.getMode();
@@ -1014,24 +1018,17 @@
private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
@NonNull SurfaceControl.Transaction startTransaction) {
final SurfaceControl leash = prevPipTaskChange.getLeash();
- final Rect bounds = prevPipTaskChange.getEndAbsBounds();
- final Point offset = prevPipTaskChange.getEndRelOffset();
- bounds.offset(-offset.x, -offset.y);
+ startTransaction.remove(leash);
- startTransaction.setWindowCrop(leash, null);
- startTransaction.setMatrix(leash, 1, 0, 0, 1);
- startTransaction.setCornerRadius(leash, 0);
- startTransaction.setPosition(leash, bounds.left, bounds.top);
-
- if (mHasFadeOut && prevPipTaskChange.getTaskInfo().isVisible()) {
- if (mPipAnimationController.getCurrentAnimator() != null) {
- mPipAnimationController.getCurrentAnimator().cancel();
- }
- startTransaction.setAlpha(leash, 1);
- }
mHasFadeOut = false;
mCurrentPipTaskToken = null;
- mPipOrganizer.onExitPipFinished(prevPipTaskChange.getTaskInfo());
+
+ // clean-up the state in PipTaskOrganizer if the PipTaskOrganizer#onTaskAppeared() hasn't
+ // been called yet with its leash reference now pointing to a new SurfaceControl not
+ // matching the leash of the pip we are removing.
+ if (mPipOrganizer.getSurfaceControl() == leash) {
+ mPipOrganizer.onExitPipFinished(prevPipTaskChange.getTaskInfo());
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 2fff0e4..e1bcd70c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -38,6 +38,7 @@
import androidx.annotation.NonNull;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -223,6 +224,13 @@
return false;
}
+ /** Whether a particular package is same as current pip package. */
+ public boolean isInPipPackage(String packageName) {
+ final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
+ return packageName != null && inPipTask != null
+ && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+ }
+
/** Add PiP-related changes to `outWCT` for the given request. */
public void augmentRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index db6138a..b5f4483 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -140,6 +140,24 @@
return state == ENTERING_PIP;
}
+ private String stateToString() {
+ switch (mState) {
+ case UNDEFINED: return "undefined";
+ case TASK_APPEARED: return "task-appeared";
+ case ENTRY_SCHEDULED: return "entry-scheduled";
+ case ENTERING_PIP: return "entering-pip";
+ case ENTERED_PIP: return "entered-pip";
+ case EXITING_PIP: return "exiting-pip";
+ }
+ throw new IllegalStateException("Unknown state: " + mState);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)",
+ stateToString(), mInSwipePipToHomeTransition);
+ }
+
public interface OnPipTransitionStateChangedListener {
void onPipTransitionStateChanged(@TransitionState int oldState,
@TransitionState int newState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index e7a1395..5e1b6be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -31,6 +31,8 @@
import android.util.Size;
import android.view.MotionEvent;
import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import com.android.internal.protolog.common.ProtoLog;
@@ -131,6 +133,8 @@
private PipMenuView mPipMenuView;
+ private SurfaceControl mLeash;
+
private ActionListener mMediaActionListener = new ActionListener() {
@Override
public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
@@ -166,6 +170,7 @@
*/
@Override
public void attach(SurfaceControl leash) {
+ mLeash = leash;
attachPipMenuView();
}
@@ -176,6 +181,7 @@
public void detach() {
hideMenu();
detachPipMenuView();
+ mLeash = null;
}
void attachPipMenuView() {
@@ -185,6 +191,36 @@
}
mPipMenuView = new PipMenuView(mContext, this, mMainExecutor, mMainHandler,
mSplitScreenController, mPipUiEventLogger);
+ mPipMenuView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ v.getViewRootImpl().addSurfaceChangedCallback(
+ new ViewRootImpl.SurfaceChangedCallback() {
+ @Override
+ public void surfaceCreated(SurfaceControl.Transaction t) {
+ final SurfaceControl sc = getSurfaceControl();
+ if (sc != null) {
+ t.reparent(sc, mLeash);
+ // make menu on top of the surface
+ t.setLayer(sc, Integer.MAX_VALUE);
+ }
+ }
+
+ @Override
+ public void surfaceReplaced(SurfaceControl.Transaction t) {
+ }
+
+ @Override
+ public void surfaceDestroyed() {
+ }
+ });
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ });
+
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
@@ -321,30 +357,10 @@
return;
}
- // If there is no pip leash supplied, that means the PiP leash is already finalized
- // resizing and the PiP menu is also resized. We then want to do a scale from the current
- // new menu bounds.
+ // TODO(b/286307861) transaction should be applied outside of PiP menu controller
if (pipLeash != null && t != null) {
- mPipMenuView.getBoundsOnScreen(mTmpSourceBounds);
- } else {
- mTmpSourceBounds.set(0, 0, destinationBounds.width(), destinationBounds.height());
+ t.apply();
}
-
- mTmpSourceRectF.set(mTmpSourceBounds);
- mTmpDestinationRectF.set(destinationBounds);
- mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
- final SurfaceControl surfaceControl = getSurfaceControl();
- if (surfaceControl == null) {
- return;
- }
- final SurfaceControl.Transaction menuTx =
- mSurfaceControlTransactionFactory.getTransaction();
- menuTx.setMatrix(surfaceControl, mMoveTransform, mTmpTransform);
- if (pipLeash != null && t != null) {
- // Merge the two transactions, vsyncId has been set on menuTx.
- menuTx.merge(t);
- }
- menuTx.apply();
}
/**
@@ -362,18 +378,10 @@
return;
}
- final SurfaceControl surfaceControl = getSurfaceControl();
- if (surfaceControl == null) {
- return;
- }
- final SurfaceControl.Transaction menuTx =
- mSurfaceControlTransactionFactory.getTransaction();
- menuTx.setCrop(surfaceControl, destinationBounds);
+ // TODO(b/286307861) transaction should be applied outside of PiP menu controller
if (pipLeash != null && t != null) {
- // Merge the two transactions, vsyncId has been set on menuTx.
- menuTx.merge(t);
+ t.apply();
}
- menuTx.apply();
}
private boolean checkPipMenuState() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 6a861ce..65727b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -574,6 +574,8 @@
@Override
public void onActivityPinned(String packageName, int userId, int taskId,
int stackId) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onActivityPinned: %s", packageName);
mTouchHandler.onActivityPinned();
mMediaController.onActivityPinned();
mAppOpsListener.onActivityPinned(packageName);
@@ -585,6 +587,8 @@
final Pair<ComponentName, Integer> topPipActivityInfo =
PipUtils.getTopPipActivity(mContext);
final ComponentName topActivity = topPipActivityInfo.first;
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onActivityUnpinned: %s", topActivity);
mTouchHandler.onActivityUnpinned(topActivity);
mAppOpsListener.onActivityUnpinned();
mPipInputConsumer.unregisterInputConsumer();
@@ -593,6 +597,8 @@
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "onActivityRestartAttempt: %s", task.topActivity);
if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
index 82fe38c..7971c04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -135,14 +135,14 @@
maxWidth = (int) (mOptimizedAspectRatio * shorterLength
+ shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
+ aspectRatio));
- maxHeight = (int) (maxWidth / aspectRatio);
+ maxHeight = Math.round(maxWidth / aspectRatio);
} else {
if (aspectRatio > 1f) {
maxWidth = shorterLength;
- maxHeight = (int) (maxWidth / aspectRatio);
+ maxHeight = Math.round(maxWidth / aspectRatio);
} else {
maxHeight = shorterLength;
- maxWidth = (int) (maxHeight * aspectRatio);
+ maxWidth = Math.round(maxHeight * aspectRatio);
}
}
@@ -165,10 +165,9 @@
Size maxSize = this.getMaxSize(aspectRatio);
- int defaultWidth = Math.max((int) (maxSize.getWidth() * mDefaultSizePercent),
+ int defaultWidth = Math.max(Math.round(maxSize.getWidth() * mDefaultSizePercent),
minSize.getWidth());
- int defaultHeight = Math.max((int) (maxSize.getHeight() * mDefaultSizePercent),
- minSize.getHeight());
+ int defaultHeight = Math.round(defaultWidth / aspectRatio);
return new Size(defaultWidth, defaultHeight);
}
@@ -188,16 +187,16 @@
Size maxSize = this.getMaxSize(aspectRatio);
- int minWidth = (int) (maxSize.getWidth() * mMinimumSizePercent);
- int minHeight = (int) (maxSize.getHeight() * mMinimumSizePercent);
+ int minWidth = Math.round(maxSize.getWidth() * mMinimumSizePercent);
+ int minHeight = Math.round(maxSize.getHeight() * mMinimumSizePercent);
// make sure the calculated min size is not smaller than the allowed default min size
if (aspectRatio > 1f) {
- minHeight = (int) Math.max(minHeight, mDefaultMinSize);
- minWidth = (int) (minHeight * aspectRatio);
+ minHeight = Math.max(minHeight, mDefaultMinSize);
+ minWidth = Math.round(minHeight * aspectRatio);
} else {
- minWidth = (int) Math.max(minWidth, mDefaultMinSize);
- minHeight = (int) (minWidth / aspectRatio);
+ minWidth = Math.max(minWidth, mDefaultMinSize);
+ minHeight = Math.round(minWidth / aspectRatio);
}
return new Size(minWidth, minHeight);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 2a61445..b0fa993 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -49,7 +49,7 @@
Consts.TAG_WM_SPLIT_SCREEN),
WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
- WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_FLOATING_APPS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
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 8723f9b..a612f5f 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
@@ -595,9 +595,20 @@
cancel(mWillFinishToHome, true /* withScreenshots */, "display change");
return;
}
- // Don't consider order-only changes as changing apps.
- if (!TransitionUtil.isOrderOnly(change)) {
+ // Don't consider order-only & non-leaf changes as changing apps.
+ if (!TransitionUtil.isOrderOnly(change) && isLeafTask) {
hasChangingApp = true;
+ } else if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME
+ && !mRecentsTask.equals(change.getContainer())) {
+ // Unless it is a 3p launcher. This means that the 3p launcher was already
+ // visible (eg. the "pausing" task is translucent over the 3p launcher).
+ // Treat it as if we are "re-opening" the 3p launcher.
+ if (openingTasks == null) {
+ openingTasks = new ArrayList<>();
+ openingTaskIsLeafs = new IntArray();
+ }
+ openingTasks.add(change);
+ openingTaskIsLeafs.add(1);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 89538cb..e52235f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -24,6 +24,9 @@
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+
+import java.util.Optional;
/**
* Main stage for split-screen mode. When split-screen is active all standard activity types launch
@@ -35,9 +38,10 @@
MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider);
+ iconProvider, windowDecorViewModel);
}
boolean isActive() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 8639b36..9903113 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -25,6 +25,9 @@
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+
+import java.util.Optional;
/**
* Side stage for split-screen mode. Only tasks that are explicitly pinned to this stage show up
@@ -37,9 +40,10 @@
SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider);
+ iconProvider, windowDecorViewModel);
}
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
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 d0ea611..e294229 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
@@ -89,11 +89,13 @@
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -172,6 +174,7 @@
private final IconProvider mIconProvider;
private final Optional<RecentTasksController> mRecentTasksOptional;
private final LaunchAdjacentController mLaunchAdjacentController;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
private final String[] mAppsSupportMultiInstances;
@@ -199,6 +202,7 @@
IconProvider iconProvider,
Optional<RecentTasksController> recentTasks,
LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel,
ShellExecutor mainExecutor) {
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
@@ -216,6 +220,7 @@
mIconProvider = iconProvider;
mRecentTasksOptional = recentTasks;
mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
@@ -246,6 +251,7 @@
IconProvider iconProvider,
RecentTasksController recentTasks,
LaunchAdjacentController launchAdjacentController,
+ WindowDecorViewModel windowDecorViewModel,
ShellExecutor mainExecutor,
StageCoordinator stageCoordinator) {
mShellCommandHandler = shellCommandHandler;
@@ -264,6 +270,7 @@
mIconProvider = iconProvider;
mRecentTasksOptional = Optional.of(recentTasks);
mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = Optional.of(windowDecorViewModel);
mStageCoordinator = stageCoordinator;
mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
shellInit.addInitCallback(this::onInit, this);
@@ -296,13 +303,15 @@
mStageCoordinator = createStageCoordinator();
}
mDragAndDropController.ifPresent(controller -> controller.setSplitScreenController(this));
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.setSplitScreenController(this));
}
protected StageCoordinator createStageCoordinator() {
return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mDisplayController, mDisplayImeController,
- mDisplayInsetsController, mTransitions, mTransactionPool,
- mIconProvider, mMainExecutor, mRecentTasksOptional, mLaunchAdjacentController);
+ mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
+ mMainExecutor, mRecentTasksOptional, mLaunchAdjacentController,
+ mWindowDecorViewModel);
}
@Override
@@ -338,6 +347,11 @@
return mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
}
+ /** Get the split stage of task is under it. */
+ public @StageType int getStageOfTask(int taskId) {
+ return mStageCoordinator.getStageOfTask(taskId);
+ }
+
/** Check split is foreground and task is under split or not by taskId. */
public boolean isTaskInSplitScreenForeground(int taskId) {
return isTaskInSplitScreen(taskId) && isSplitScreenVisible();
@@ -384,17 +398,35 @@
mStageCoordinator.setSideStagePosition(sideStagePosition, null /* wct */);
}
- public void enterSplitScreen(int taskId, boolean leftOrTop) {
- enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
- }
-
+ /**
+ * Doing necessary window transaction for other transition handler need to enter split in
+ * transition.
+ */
public void prepareEnterSplitScreen(WindowContainerTransaction wct,
ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
- mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition);
+ mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition,
+ false /* resizeAnim */);
}
- public void finishEnterSplitScreen(SurfaceControl.Transaction t) {
- mStageCoordinator.finishEnterSplitScreen(t);
+ /**
+ * Doing necessary surface transaction for other transition handler need to enter split in
+ * transition when finished.
+ */
+ public void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
+ mStageCoordinator.finishEnterSplitScreen(finishT);
+ }
+
+ /**
+ * Doing necessary window transaction for other transition handler need to exit split in
+ * transition.
+ */
+ public void prepareExitSplitScreen(WindowContainerTransaction wct,
+ @StageType int stageToTop) {
+ mStageCoordinator.prepareExitSplitScreen(stageToTop, wct);
+ }
+
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
}
public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 9863099..d21f8a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -199,19 +199,7 @@
boolean isOpening = TransitionUtil.isOpeningType(info.getType());
if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
// fade out
- if (change.getSnapshot() != null) {
- // This case is happened if task is going to reparent to TDA, the origin leash
- // doesn't rendor so we use snapshot to replace it animating.
- t.reparent(change.getSnapshot(), info.getRoot(rootIdx).getLeash());
- // Use origin leash layer.
- t.setLayer(change.getSnapshot(), info.getChanges().size() - i);
- t.setPosition(change.getSnapshot(), change.getStartAbsBounds().left,
- change.getStartAbsBounds().top);
- t.show(change.getSnapshot());
- startFadeAnimation(change.getSnapshot(), false /* show */);
- } else {
- startFadeAnimation(leash, false /* show */);
- }
+ startFadeAnimation(leash, false /* show */);
} else if (mode == TRANSIT_CHANGE && change.getSnapshot() != null) {
t.reparent(change.getSnapshot(), info.getRoot(rootIdx).getLeash());
// Ensure snapshot it on the top of all transition surfaces
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8497f9f..b5d4a9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -122,7 +122,6 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
@@ -141,6 +140,7 @@
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.SplitBounds;
import com.android.wm.shell.util.TransitionUtil;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -172,7 +172,6 @@
private final StageListenerImpl mMainStageListener = new StageListenerImpl();
private final SideStage mSideStage;
private final StageListenerImpl mSideStageListener = new StageListenerImpl();
- private final DisplayLayout mDisplayLayout;
@SplitPosition
private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -198,6 +197,7 @@
private final ArrayList<Integer> mPausingTasks = new ArrayList<>();
private final Optional<RecentTasksController> mRecentTasks;
private final LaunchAdjacentController mLaunchAdjacentController;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
private final Rect mTempRect1 = new Rect();
private final Rect mTempRect2 = new Rect();
@@ -276,7 +276,8 @@
TransactionPool transactionPool,
IconProvider iconProvider, ShellExecutor mainExecutor,
Optional<RecentTasksController> recentTasks,
- LaunchAdjacentController launchAdjacentController) {
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -285,6 +286,7 @@
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
@@ -295,7 +297,8 @@
mMainStageListener,
mSyncQueue,
mSurfaceSession,
- iconProvider);
+ iconProvider,
+ mWindowDecorViewModel);
mSideStage = new SideStage(
mContext,
mTaskOrganizer,
@@ -303,7 +306,8 @@
mSideStageListener,
mSyncQueue,
mSurfaceSession,
- iconProvider);
+ iconProvider,
+ mWindowDecorViewModel);
mDisplayController = displayController;
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
@@ -315,7 +319,6 @@
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
this::onTransitionAnimationComplete, this);
mDisplayController.addDisplayWindowListener(this);
- mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
transitions.addHandler(this);
mSplitUnsupportedToast = Toast.makeText(mContext,
R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT);
@@ -332,7 +335,8 @@
Transitions transitions, TransactionPool transactionPool,
ShellExecutor mainExecutor,
Optional<RecentTasksController> recentTasks,
- LaunchAdjacentController launchAdjacentController) {
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
@@ -350,8 +354,8 @@
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
mLaunchAdjacentController = launchAdjacentController;
+ mWindowDecorViewModel = windowDecorViewModel;
mDisplayController.addDisplayWindowListener(this);
- mDisplayLayout = new DisplayLayout();
transitions.addHandler(this);
mSplitUnsupportedToast = Toast.makeText(mContext,
R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT);
@@ -399,7 +403,7 @@
boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
WindowContainerTransaction wct) {
- prepareEnterSplitScreen(wct, task, stagePosition);
+ prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */);
if (ENABLE_SHELL_TRANSITIONS) {
mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
null, this,
@@ -497,20 +501,26 @@
/** Launches an activity into split. */
void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
@Nullable Bundle options) {
+ mSplitRequest = new SplitRequest(intent.getIntent(), position);
if (!ENABLE_SHELL_TRANSITIONS) {
startIntentLegacy(intent, fillInIntent, position, options);
return;
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
-
options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
wct.sendPendingIntent(intent, fillInIntent, options);
+ // If this should be mixed, just send the intent to avoid split handle transition directly.
+ if (mMixedHandler != null && mMixedHandler.shouldSplitEnterMixed(intent)) {
+ mTaskOrganizer.applyTransaction(wct);
+ return;
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
- prepareEnterSplitScreen(wct, null /* taskInfo */, position);
+ prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
extraTransitType, !mIsDropEntering);
@@ -567,7 +577,6 @@
if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) {
updateWindowBounds(mSplitLayout, wct);
}
- mSplitRequest = new SplitRequest(intent.getIntent(), position);
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
@@ -1455,7 +1464,7 @@
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
* to be used when exiting split might be bundled with other window operations.
*/
- private void prepareExitSplitScreen(@StageType int stageToTop,
+ void prepareExitSplitScreen(@StageType int stageToTop,
@NonNull WindowContainerTransaction wct) {
if (!mMainStage.isActive()) return;
mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
@@ -1463,7 +1472,8 @@
}
private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
- prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED);
+ prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED,
+ !mIsDropEntering);
}
/**
@@ -1471,51 +1481,62 @@
* into side stage.
*/
void prepareEnterSplitScreen(WindowContainerTransaction wct,
- @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+ boolean resizeAnim) {
onSplitScreenEnter();
if (isSplitActive()) {
- prepareBringSplit(wct, taskInfo, startPosition);
+ prepareBringSplit(wct, taskInfo, startPosition, resizeAnim);
} else {
- prepareActiveSplit(wct, taskInfo, startPosition);
+ prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim);
}
}
private void prepareBringSplit(WindowContainerTransaction wct,
- @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+ boolean resizeAnim) {
if (taskInfo != null) {
wct.startTask(taskInfo.taskId,
resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
}
// If running background, we need to reparent current top visible task to main stage.
if (!isSplitScreenVisible()) {
+ // Ensure to evict old splitting tasks because the new split pair might be composed by
+ // one of the splitting tasks, evicting the task when finishing entering transition
+ // won't guarantee to put the task to the indicated new position.
+ mMainStage.evictAllChildren(wct);
mMainStage.reparentTopTask(wct);
- prepareSplitLayout(wct);
+ prepareSplitLayout(wct, resizeAnim);
}
}
private void prepareActiveSplit(WindowContainerTransaction wct,
- @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
+ boolean resizeAnim) {
if (!ENABLE_SHELL_TRANSITIONS) {
// Legacy transition we need to create divider here, shell transition case we will
// create it on #finishEnterSplitScreen
mSplitLayout.init();
+ } else {
+ // We handle split visibility itself on shell transition, but sometimes we didn't
+ // reset it correctly after dismiss by some reason, so just set invisible before active.
+ setSplitsVisible(false);
}
if (taskInfo != null) {
setSideStagePosition(startPosition, wct);
mSideStage.addTask(taskInfo, wct);
}
mMainStage.activate(wct, true /* includingTopTask */);
- prepareSplitLayout(wct);
+ prepareSplitLayout(wct, resizeAnim);
}
- private void prepareSplitLayout(WindowContainerTransaction wct) {
- if (mIsDropEntering) {
- mSplitLayout.resetDividerPosition();
- } else {
+ private void prepareSplitLayout(WindowContainerTransaction wct, boolean resizeAnim) {
+ if (resizeAnim) {
mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+ } else {
+ mSplitLayout.resetDividerPosition();
}
updateWindowBounds(mSplitLayout, wct);
- if (!mIsDropEntering) {
+ if (resizeAnim) {
// Reset its smallest width dp to avoid is change layout before it actually resized to
// split bounds.
wct.setSmallestScreenWidthDp(mMainStage.mRootTaskInfo.token,
@@ -1525,21 +1546,22 @@
setRootForceTranslucent(false, wct);
}
- void finishEnterSplitScreen(SurfaceControl.Transaction t) {
- mSplitLayout.update(t);
+ void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
+ mSplitLayout.update(finishT);
mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
getMainStageBounds());
mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
getSideStageBounds());
- setDividerVisibility(true, t);
+ setDividerVisibility(true, finishT);
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
- t.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
+ finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- t.show(mRootTaskLeash);
+ updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */);
+ finishT.show(mRootTaskLeash);
setSplitsVisible(true);
mIsDropEntering = false;
+ mSplitRequest = null;
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
@@ -1632,7 +1654,7 @@
mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
mSplitLayout.isLandscape());
}
- if (present && visible) {
+ if (present) {
updateRecentTasksSplitPair();
}
@@ -1691,7 +1713,7 @@
if (mSplitLayout == null) {
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mRootTaskInfo.configuration, this, mParentContainerCallbacks,
- mDisplayImeController, mTaskOrganizer,
+ mDisplayController, mDisplayImeController, mTaskOrganizer,
PARALLAX_ALIGN_CENTER /* parallaxType */);
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
}
@@ -1705,7 +1727,7 @@
if (mRootTaskInfo == null || mRootTaskInfo.taskId != taskInfo.taskId) {
throw new IllegalArgumentException(this + "\n Unknown task info changed: " + taskInfo);
}
-
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
mRootTaskInfo = taskInfo;
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
@@ -2153,8 +2175,6 @@
if (displayId != DEFAULT_DISPLAY) {
return;
}
- mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
-
if (mSplitLayout != null && mSplitLayout.isDensityChanged(newConfig.densityDpi)
&& mMainStage.isActive()
&& mSplitLayout.updateConfiguration(newConfig)
@@ -2171,10 +2191,9 @@
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
- if (!mMainStage.isActive()) return;
+ if (displayId != DEFAULT_DISPLAY || !mMainStage.isActive()) return;
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
- mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
+ mSplitLayout.rotateTo(toRotation);
if (newDisplayAreaInfo != null) {
mSplitLayout.updateConfiguration(newDisplayAreaInfo.configuration);
}
@@ -2315,8 +2334,8 @@
mSplitTransitions.setDismissTransition(transition, dismissTop,
EXIT_REASON_APP_FINISHED);
} else if (!isSplitScreenVisible() && isOpening) {
- // If split running backgroud and trigger task is appearing into split,
- // prepare to enter split screen.
+ // If split is running in the background and the trigger task is appearing into
+ // split, prepare to enter split screen.
prepareEnterSplitScreen(out);
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
@@ -2497,6 +2516,8 @@
// handling to the mixed-handler to deal with splitting it up.
if (mMixedHandler.animatePendingSplitWithDisplayChange(transition, info,
startTransaction, finishTransaction, finishCallback)) {
+ mSplitLayout.update(startTransaction);
+ startTransaction.apply();
return true;
}
}
@@ -2635,11 +2656,11 @@
if (mSplitTransitions.mPendingEnter.mExtraTransitType
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
+ // Open to side should only be used when split already active and foregorund.
if (mainChild == null && sideChild == null) {
Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
- mSplitTransitions.mPendingEnter.cancel((cancelWct, cancelT)
- -> prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, cancelWct));
- mSplitUnsupportedToast.show();
+ // This should happen when the target app is already on front, so just cancel.
+ mSplitTransitions.mPendingEnter.cancel(null);
return true;
}
} else {
@@ -2881,6 +2902,12 @@
/** Call this when the recents animation canceled during split-screen. */
public void onRecentsInSplitAnimationCanceled() {
mPausingTasks.clear();
+ setSplitsVisible(false);
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+ true /* reparentLeafTaskIfRelaunch */);
+ mTaskOrganizer.applyTransaction(wct);
}
/** Call this when the recents animation during split-screen finishes. */
@@ -2905,8 +2932,8 @@
}
setSplitsVisible(false);
- prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct);
- logExit(EXIT_REASON_UNKNOWN);
+ finishWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+ true /* reparentLeafTaskIfRelaunch */);
}
/** Call this when the recents animation finishes by doing pair-to-pair switch. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 92ff5fe..3ef4f02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -51,8 +51,10 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.io.PrintWriter;
+import java.util.Optional;
import java.util.function.Predicate;
/**
@@ -87,6 +89,7 @@
private final SurfaceSession mSurfaceSession;
private final SyncTransactionQueue mSyncQueue;
private final IconProvider mIconProvider;
+ private final Optional<WindowDecorViewModel> mWindowDecorViewModel;
protected ActivityManager.RunningTaskInfo mRootTaskInfo;
protected SurfaceControl mRootLeash;
@@ -98,12 +101,14 @@
StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider) {
+ SurfaceSession surfaceSession, IconProvider iconProvider,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
mContext = context;
mCallbacks = callbacks;
mSyncQueue = syncQueue;
mSurfaceSession = surfaceSession;
mIconProvider = iconProvider;
+ mWindowDecorViewModel = windowDecorViewModel;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}
@@ -127,7 +132,8 @@
* Returns the top visible child task's id.
*/
int getTopVisibleChildTaskId() {
- final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible);
+ final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible
+ && t.isVisibleRequested);
return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
}
@@ -183,12 +189,13 @@
final int taskId = taskInfo.taskId;
mChildrenLeashes.put(taskId, leash);
mChildrenTaskInfo.put(taskId, taskInfo);
- updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
- mCallbacks.onChildTaskStatusChanged(taskId, true /* present */, taskInfo.isVisible);
+ mCallbacks.onChildTaskStatusChanged(taskId, true /* present */,
+ taskInfo.isVisible && taskInfo.isVisibleRequested);
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
return;
}
+ updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
mCallbacks.onChildTaskAppeared(taskId);
sendStatusChanged();
} else {
@@ -200,6 +207,7 @@
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) {
@@ -223,7 +231,7 @@
}
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
- taskInfo.isVisible);
+ taskInfo.isVisible && taskInfo.isVisibleRequested);
if (!ENABLE_SHELL_TRANSITIONS) {
updateChildTaskSurface(
taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
@@ -417,7 +425,7 @@
}
t.setCrop(leash, null);
t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
- if (firstAppeared && !ENABLE_SHELL_TRANSITIONS) {
+ if (firstAppeared) {
t.setAlpha(leash, 1f);
t.setMatrix(leash, 1, 0, 0, 1);
t.show(leash);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
index f05f324..a2301b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -86,7 +86,8 @@
super(context, shellInit, shellCommandHandler, shellController, shellTaskOrganizer,
syncQueue, rootTDAOrganizer, displayController, displayImeController,
displayInsetsController, dragAndDropController, transitions, transactionPool,
- iconProvider, recentTasks, launchAdjacentController, mainExecutor);
+ iconProvider, recentTasks, launchAdjacentController, Optional.empty(),
+ mainExecutor);
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
index 0b11922..7947691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
@@ -56,7 +56,7 @@
SystemWindows systemWindows) {
super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
displayInsetsController, transitions, transactionPool, iconProvider,
- mainExecutor, recentTasks, launchAdjacentController);
+ mainExecutor, recentTasks, launchAdjacentController, Optional.empty());
mTvSplitMenuController = new TvSplitMenuController(context, this,
systemWindows, mainHandler);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
index ae72220..4cfbbd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
@@ -20,6 +20,7 @@
import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -370,8 +371,11 @@
mStartingWindowRecordManager.addRecord(taskId, tView);
}
- private void removeWindowInner(View decorView, boolean hideView) {
+ private void removeWindowInner(@NonNull View decorView, boolean hideView) {
requestTopUi(false);
+ if (!decorView.isAttachedToWindow()) {
+ return;
+ }
if (hideView) {
decorView.setVisibility(View.GONE);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index 1bbd367..163cf50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -61,6 +61,16 @@
private TaskViewBase mTaskViewBase;
private final Context mContext;
+ /**
+ * There could be a situation where we have task info and receive
+ * {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)}, however, the
+ * activity might fail to open, and in this case we need to clean up the task view / notify
+ * listeners of a task removal. This requires task info, so we save the info from onTaskAppeared
+ * in this situation to allow us to notify listeners correctly if the task failed to open.
+ */
+ private ActivityManager.RunningTaskInfo mPendingInfo;
+ /* Indicates that the task we attempted to launch in the task view failed to launch. */
+ private boolean mTaskNotFound;
protected ActivityManager.RunningTaskInfo mTaskInfo;
private WindowContainerToken mTaskToken;
private SurfaceControl mTaskLeash;
@@ -236,6 +246,8 @@
mTaskInfo = null;
mTaskToken = null;
mTaskLeash = null;
+ mPendingInfo = null;
+ mTaskNotFound = false;
}
private void updateTaskVisibility() {
@@ -257,6 +269,12 @@
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl leash) {
if (isUsingShellTransitions()) {
+ mPendingInfo = taskInfo;
+ if (mTaskNotFound) {
+ // If we were already notified by shell transit that we don't have the
+ // the task, clean it up now.
+ cleanUpPendingTask();
+ }
// Everything else handled by enter transition.
return;
}
@@ -455,6 +473,42 @@
return mTaskInfo;
}
+ /**
+ * Indicates that the task was not found in the start animation for the transition.
+ * In this case we should clean up the task if we have the pending info. If we don't
+ * have the pending info, we'll do it when we receive it in
+ * {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)}.
+ */
+ void setTaskNotFound() {
+ mTaskNotFound = true;
+ if (mPendingInfo != null) {
+ cleanUpPendingTask();
+ }
+ }
+
+ /**
+ * Called when a task failed to open and we need to clean up task view /
+ * notify users of task view.
+ */
+ void cleanUpPendingTask() {
+ if (mPendingInfo != null) {
+ if (mListener != null) {
+ final int taskId = mPendingInfo.taskId;
+ mListenerExecutor.execute(() -> {
+ mListener.onTaskRemovalStarted(taskId);
+ });
+ }
+ mTaskViewBase.onTaskVanished(mPendingInfo);
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mPendingInfo.token, false);
+
+ // Make sure the task is removed
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.removeTask(mPendingInfo.token);
+ mTaskViewTransitions.closeTaskView(wct, this);
+ }
+ resetTaskInfo();
+ }
+
void prepareHideAnimation(@NonNull SurfaceControl.Transaction finishTransaction) {
if (mTaskToken == null) {
// Nothing to update, task is not yet available
@@ -492,6 +546,7 @@
@NonNull SurfaceControl.Transaction finishTransaction,
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash,
WindowContainerTransaction wct) {
+ mPendingInfo = null;
mTaskInfo = taskInfo;
mTaskToken = mTaskInfo.token;
mTaskLeash = leash;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index fe2faaf..944acb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -135,6 +135,22 @@
}
/**
+ * Looks through the pending transitions for a opening transaction that matches the provided
+ * `taskView`.
+ * @param taskView the pending transition should be for this.
+ */
+ @VisibleForTesting
+ PendingTransition findPendingOpeningTransition(TaskViewTaskController taskView) {
+ for (int i = mPending.size() - 1; i >= 0; --i) {
+ if (mPending.get(i).mTaskView != taskView) continue;
+ if (TransitionUtil.isOpeningType(mPending.get(i).mType)) {
+ return mPending.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
* Looks through the pending transitions for one matching `taskView`.
* @param taskView the pending transition should be for this.
* @param type the type of transition it's looking for
@@ -369,10 +385,11 @@
}
}
if (stillNeedsMatchingLaunch) {
- throw new IllegalStateException("Expected a TaskView launch in this transition but"
- + " didn't get one.");
- }
- if (wct == null && pending == null && changesHandled != info.getChanges().size()) {
+ Slog.w(TAG, "Expected a TaskView launch in this transition but didn't get one, "
+ + "cleaning up the task view");
+ // Didn't find a task so the task must have never launched
+ pending.mTaskView.setTaskNotFound();
+ } else if (wct == null && pending == null && changesHandled != info.getChanges().size()) {
// Just some house-keeping, let another handler animate.
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index f58f24b..bda25d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -24,12 +24,14 @@
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.util.TransitionUtil.isOpeningType;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.os.IBinder;
import android.util.Log;
import android.util.Pair;
@@ -44,6 +46,7 @@
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
+import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -170,7 +173,9 @@
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()) {
+ if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()
+ && request.getTriggerTask() != null && mSplitHandler.getSplitItemPosition(
+ request.getTriggerTask().token) != SPLIT_POSITION_UNDEFINED) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while "
+ "Split-Screen is active, so treat it as Mixed.");
if (request.getRemoteTransition() != null) {
@@ -637,6 +642,17 @@
return false;
}
+ /** Use to when split use intent to enter, check if this enter transition should be mixed or
+ * not.*/
+ public boolean shouldSplitEnterMixed(PendingIntent intent) {
+ // Check if this intent package is same as pip one or not, if true we want let the pip
+ // task enter split.
+ if (mPipHandler != null) {
+ return mPipHandler.isInPipPackage(SplitScreenUtils.getPackageName(intent.getIntent()));
+ }
+ return false;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
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 4c678a2..e52fd00 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
@@ -58,7 +58,6 @@
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
-import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
import static com.android.wm.shell.transition.TransitionAnimationHelper.edgeExtendWindow;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
@@ -76,6 +75,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
@@ -103,6 +103,7 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
@@ -137,6 +138,7 @@
private final Rect mInsets = new Rect(0, 0, 0, 0);
private float mTransitionAnimationScaleSetting = 1.0f;
+ private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
private final int mCurrentUserId;
private Drawable mEnterpriseThumbnailDrawable;
@@ -157,7 +159,8 @@
@NonNull DisplayController displayController,
@NonNull TransactionPool transactionPool,
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
- @NonNull ShellExecutor animExecutor) {
+ @NonNull ShellExecutor animExecutor,
+ @NonNull RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
mDisplayController = displayController;
mTransactionPool = transactionPool;
mContext = context;
@@ -168,6 +171,7 @@
mCurrentUserId = UserHandle.myUserId();
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
shellInit.addInitCallback(this::onInit, this);
+ mRootTDAOrganizer = rootTDAOrganizer;
}
private void onInit() {
@@ -256,6 +260,12 @@
// This is the only way to get display-id currently, so check display capabilities here.
final DisplayLayout displayLayout = displayController.getDisplayLayout(
topTaskInfo.displayId);
+ // This condition should be true when using gesture navigation or the screen size is large
+ // (>600dp) because the bar is small relative to screen.
+ if (displayLayout.allowSeamlessRotationDespiteNavBarMoving()) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " nav bar allows seamless.");
+ return ROTATION_ANIMATION_SEAMLESS;
+ }
// For the upside down rotation we don't rotate seamlessly as the navigation bar moves
// position. Note most apps (using orientation:sensor or user as opposed to fullSensor)
// will not enter the reverse portrait orientation, so actually the orientation won't
@@ -268,13 +278,9 @@
return animationHint;
}
- // If the navigation bar can't change sides, then it will jump when we change orientations
- // and we don't rotate seamlessly - unless that is allowed, e.g. with gesture navigation
- // where the navbar is low-profile enough that this isn't very noticeable.
- if (!displayLayout.allowSeamlessRotationDespiteNavBarMoving()
- && (!(displayLayout.navigationBarCanMove()
- && (displayChange.getStartAbsBounds().width()
- != displayChange.getStartAbsBounds().height())))) {
+ // If the navigation bar cannot change sides, then it will jump when changing orientation
+ // so do not use seamless rotation.
+ if (!displayLayout.navigationBarCanMove()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
" nav bar changes sides, so not seamless.");
return animationHint;
@@ -510,10 +516,8 @@
}
if (backgroundColorForTransition != 0) {
- for (int i = 0; i < info.getRootCount(); ++i) {
- addBackgroundToTransition(info.getRoot(i).getLeash(), backgroundColorForTransition,
- startTransaction, finishTransaction);
- }
+ addBackgroundColorOnTDA(info, backgroundColorForTransition, startTransaction,
+ finishTransaction);
}
if (postStartTransactionCallbacks.size() > 0) {
@@ -543,6 +547,28 @@
return true;
}
+ private void addBackgroundColorOnTDA(@NonNull TransitionInfo info,
+ @ColorInt int color, @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ final Color bgColor = Color.valueOf(color);
+ final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
+
+ for (int i = 0; i < info.getRootCount(); ++i) {
+ final int displayId = info.getRoot(i).getDisplayId();
+ final SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder()
+ .setName("animation-background")
+ .setCallsite("DefaultTransitionHandler")
+ .setColorLayer();
+
+ mRootTDAOrganizer.attachToDisplayArea(displayId, colorLayerBuilder);
+ final SurfaceControl backgroundSurface = colorLayerBuilder.build();
+ startTransaction.setColor(backgroundSurface, colorArray)
+ .setLayer(backgroundSurface, -1)
+ .show(backgroundSurface);
+ finishTransaction.remove(backgroundSurface);
+ }
+ }
+
private static boolean isDreamTransition(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -696,9 +722,10 @@
if (a != null) {
if (!a.isInitialized()) {
- final int width = endBounds.width();
- final int height = endBounds.height();
- a.initialize(width, height, width, height);
+ final Rect animationRange = TransitionUtil.isClosingType(changeMode)
+ ? change.getStartAbsBounds() : change.getEndAbsBounds();
+ a.initialize(animationRange.width(), animationRange.height(),
+ endBounds.width(), endBounds.height());
}
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
@@ -873,18 +900,31 @@
}
}
+ /**
+ * Returns {@code true} if the default transition handler can run the override animation.
+ * @see #loadAnimation(TransitionInfo, TransitionInfo.Change, int, boolean)
+ */
+ public static boolean isSupportedOverrideAnimation(
+ @NonNull TransitionInfo.AnimationOptions options) {
+ final int animType = options.getType();
+ return animType == ANIM_CUSTOM || animType == ANIM_SCALE_UP
+ || animType == ANIM_THUMBNAIL_SCALE_UP || animType == ANIM_THUMBNAIL_SCALE_DOWN
+ || animType == ANIM_CLIP_REVEAL || animType == ANIM_OPEN_CROSS_PROFILE_APPS;
+ }
+
private static void applyTransformation(long time, SurfaceControl.Transaction t,
- SurfaceControl leash, Animation anim, Transformation transformation, float[] matrix,
+ SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
Point position, float cornerRadius, @Nullable Rect immutableClipRect) {
- anim.getTransformation(time, transformation);
+ tmpTransformation.clear();
+ anim.getTransformation(time, tmpTransformation);
if (position != null) {
- transformation.getMatrix().postTranslate(position.x, position.y);
+ tmpTransformation.getMatrix().postTranslate(position.x, position.y);
}
- t.setMatrix(leash, transformation.getMatrix(), matrix);
- t.setAlpha(leash, transformation.getAlpha());
+ t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
+ t.setAlpha(leash, tmpTransformation.getAlpha());
final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
- Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
+ Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE);
if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
// Clip out any overflowing edge extension
clipRect.inset(extensionInsets);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index de20c2d..d8a8877 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -69,6 +69,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -160,6 +161,10 @@
public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE =
WindowManager.TRANSIT_FIRST_CUSTOM + 13;
+ /** Transition type to animate the toggle resize between the max and default desktop sizes. */
+ public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE =
+ WindowManager.TRANSIT_FIRST_CUSTOM + 14;
+
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
@@ -265,7 +270,8 @@
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor) {
this(context, shellInit, shellController, organizer, pool, displayController, mainExecutor,
- mainHandler, animExecutor, null);
+ mainHandler, animExecutor, null,
+ new RootTaskDisplayAreaOrganizer(mainExecutor, context));
}
public Transitions(@NonNull Context context,
@@ -277,7 +283,8 @@
@NonNull ShellExecutor mainExecutor,
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
- @Nullable ShellCommandHandler shellCommandHandler) {
+ @Nullable ShellCommandHandler shellCommandHandler,
+ @NonNull RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
mOrganizer = organizer;
mContext = context;
mMainExecutor = mainExecutor;
@@ -285,7 +292,7 @@
mDisplayController = displayController;
mPlayerImpl = new TransitionPlayerImpl();
mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit,
- displayController, pool, mainExecutor, mainHandler, animExecutor);
+ displayController, pool, mainExecutor, mainHandler, animExecutor, rootTDAOrganizer);
mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor);
mShellController = shellController;
// The very last handler (0 in the list) should be the default one.
@@ -641,6 +648,7 @@
@VisibleForTesting
void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
+ info.setUnreleasedWarningCallSiteForAllSurfaces("Transitions.onTransitionReady");
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
transitionToken, info);
final int activeIdx = findByToken(mPendingTransitions, transitionToken);
@@ -805,6 +813,9 @@
track.mReadyTransitions.remove(0);
track.mActiveTransition = ready;
if (ready.mAborted) {
+ if (ready.mStartT != null) {
+ ready.mStartT.apply();
+ }
// finish now since there's nothing to animate. Calls back into processReadyQueue
onFinish(ready, null, null);
return;
@@ -932,10 +943,6 @@
/** Aborts a transition. This will still queue it up to maintain order. */
private void onAbort(ActiveTransition transition) {
final Track track = mTracks.get(transition.getTrack());
- // apply immediately since they may be "parallel" operations: We currently we use abort for
- // thing which are independent to other transitions (like starting-window transfer).
- transition.mStartT.apply();
- transition.mFinishT.apply();
transition.mAborted = true;
mTracer.logAborted(transition.mInfo.getDebugId());
@@ -1082,9 +1089,8 @@
if (wct == null) {
wct = new WindowContainerTransaction();
}
- mDisplayController.getChangeController().dispatchOnDisplayChange(wct,
- change.getDisplayId(), change.getStartRotation(),
- change.getEndRotation(), null /* newDisplayAreaInfo */);
+ mDisplayController.onDisplayRotateRequested(wct, change.getDisplayId(),
+ change.getStartRotation(), change.getEndRotation());
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
index c33a633..936faa3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
@@ -170,6 +170,9 @@
if (isOpeningType(mode)) {
t.setAlpha(leash, 0.f);
}
+ // Set the transition leash position to 0 in case the divider leash position being
+ // taking down.
+ t.setPosition(leash, 0, 0);
t.setLayer(leash, Integer.MAX_VALUE);
return;
}
@@ -228,7 +231,11 @@
t.reparent(change.getLeash(), leashSurface);
t.setAlpha(change.getLeash(), 1.0f);
t.show(change.getLeash());
- t.setPosition(change.getLeash(), 0, 0);
+ if (!isDividerBar(change)) {
+ // For divider, don't modify its inner leash position when creating the outer leash
+ // for the transition. In case the position being wrong after the transition finished.
+ t.setPosition(change.getLeash(), 0, 0);
+ }
t.setLayer(change.getLeash(), 0);
return leashSurface;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 2267c75..92c2a7c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -33,11 +33,14 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
/**
@@ -89,6 +92,9 @@
}
@Override
+ public void setSplitScreenController(SplitScreenController splitScreenController) {}
+
+ @Override
public boolean onTaskOpening(
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
@@ -254,7 +260,7 @@
* @return {@code true} if a drag is happening; or {@code false} if it is not
*/
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 116af70..b217bd3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -113,7 +113,7 @@
mRelayoutParams.reset();
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
- mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
+ mRelayoutParams.mCaptionHeightId = getCaptionHeightId();
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
@@ -143,6 +143,7 @@
mHandler,
mChoreographer,
mDisplay.getDisplayId(),
+ 0 /* taskCornerRadius */,
mDecorationContainerSurface,
mDragPositioningCallback);
}
@@ -221,4 +222,9 @@
closeDragResizeListener();
super.close();
}
+
+ @Override
+ int getCaptionHeightId() {
+ return R.dimen.freeform_decor_caption_height;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index f0f06a6..c93a11d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -42,6 +43,7 @@
import android.os.Looper;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.GestureDetector;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventReceiver;
@@ -53,6 +55,7 @@
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -106,7 +109,7 @@
private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
private final Transitions mTransitions;
- private Optional<SplitScreenController> mSplitScreenController;
+ private SplitScreenController mSplitScreenController;
private ValueAnimator mDragToDesktopValueAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
@@ -121,8 +124,7 @@
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController) {
+ Optional<DesktopTasksController> desktopTasksController) {
this(
context,
mainHandler,
@@ -133,7 +135,6 @@
transitions,
desktopModeController,
desktopTasksController,
- splitScreenController,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
SurfaceControl.Transaction::new);
@@ -150,7 +151,6 @@
Transitions transitions,
Optional<DesktopModeController> desktopModeController,
Optional<DesktopTasksController> desktopTasksController,
- Optional<SplitScreenController> splitScreenController,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
Supplier<SurfaceControl.Transaction> transactionFactory) {
@@ -160,7 +160,6 @@
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mTaskOrganizer = taskOrganizer;
mDisplayController = displayController;
- mSplitScreenController = splitScreenController;
mSyncQueue = syncQueue;
mTransitions = transitions;
mDesktopModeController = desktopModeController;
@@ -177,6 +176,11 @@
}
@Override
+ public void setSplitScreenController(SplitScreenController splitScreenController) {
+ mSplitScreenController = splitScreenController;
+ }
+
+ @Override
public boolean onTaskOpening(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
@@ -195,7 +199,8 @@
if (change.getMode() == WindowManager.TRANSIT_CHANGE
&& (info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE
|| info.getType() == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
- || info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE)) {
+ || info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE
+ || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE)) {
mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
.addTransitionPausingRelayout(transition);
}
@@ -238,7 +243,6 @@
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
-
if (!shouldShowWindowDecor(taskInfo)) {
if (decoration != null) {
destroyWindowDecoration(taskInfo);
@@ -277,15 +281,17 @@
}
}
- private class DesktopModeTouchEventListener implements
- View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
+ private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
+ implements View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
private final int mTaskId;
private final WindowContainerToken mTaskToken;
private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
+ private final GestureDetector mGestureDetector;
private boolean mIsDragging;
+ private boolean mShouldClick;
private int mDragPointerId = -1;
private DesktopModeTouchEventListener(
@@ -295,6 +301,7 @@
mTaskToken = taskInfo.token;
mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
+ mGestureDetector = new GestureDetector(mContext, this);
}
@Override
@@ -303,14 +310,14 @@
final int id = v.getId();
if (id == R.id.close_window || id == R.id.close_button) {
mTaskOperations.closeTask(mTaskToken);
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isSplitScreenVisible()) {
- int remainingTaskPosition = mTaskId == mSplitScreenController.get()
+ if (mSplitScreenController != null
+ && mSplitScreenController.isSplitScreenVisible()) {
+ int remainingTaskPosition = mTaskId == mSplitScreenController
.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT).taskId
? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
- ActivityManager.RunningTaskInfo remainingTask = mSplitScreenController.get()
+ ActivityManager.RunningTaskInfo remainingTask = mSplitScreenController
.getTaskInfo(remainingTaskPosition);
- mSplitScreenController.get().moveTaskToFullscreen(remainingTask.taskId);
+ mSplitScreenController.moveTaskToFullscreen(remainingTask.taskId);
}
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey();
@@ -323,7 +330,13 @@
}
} else if (id == R.id.desktop_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
- mDesktopTasksController.ifPresent(c -> c.moveToDesktop(mTaskId));
+ if (mDesktopTasksController.isPresent()) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ // App sometimes draws before the insets from WindowDecoration#relayout have
+ // been added, so they must be added here
+ mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
+ mDesktopTasksController.get().moveToDesktop(mTaskId, wct);
+ }
decoration.closeHandleMenu();
} else if (id == R.id.fullscreen_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
@@ -349,7 +362,7 @@
return false;
}
moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
- return mDragDetector.onMotionEvent(e);
+ return mDragDetector.onMotionEvent(v, e);
}
private void moveTaskToFront(RunningTaskInfo taskInfo) {
@@ -364,7 +377,7 @@
* @return {@code true} if the motion event is handled.
*/
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
if (DesktopModeStatus.isProto2Enabled()
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
@@ -375,6 +388,9 @@
== WINDOWING_MODE_FULLSCREEN) {
return false;
}
+ if (mGestureDetector.onTouchEvent(e)) {
+ return true;
+ }
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDragPointerId = e.getPointerId(0);
@@ -382,7 +398,8 @@
0 /* ctrlType */, e.getRawX(0),
e.getRawY(0));
mIsDragging = false;
- return false;
+ mShouldClick = true;
+ return true;
}
case MotionEvent.ACTION_MOVE: {
final DesktopModeWindowDecoration decoration =
@@ -396,10 +413,20 @@
mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mIsDragging = true;
+ mShouldClick = false;
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
+ final boolean wasDragging = mIsDragging;
+ if (!wasDragging) {
+ if (mShouldClick && v != null) {
+ v.performClick();
+ mShouldClick = false;
+ return true;
+ }
+ return false;
+ }
if (e.findPointerIndex(mDragPointerId) == -1) {
mDragPointerId = e.getPointerId(0);
}
@@ -414,13 +441,21 @@
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
position, e.getRawY(), mWindowDecorByTaskId.get(mTaskId)));
- final boolean wasDragging = mIsDragging;
mIsDragging = false;
- return wasDragging;
+ return true;
}
}
return true;
}
+
+ @Override
+ public boolean onDoubleTap(@NonNull MotionEvent e) {
+ final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ mDesktopTasksController.ifPresent(c -> {
+ c.toggleDesktopTaskSize(taskInfo, mWindowDecorByTaskId.get(taskInfo.taskId));
+ });
+ return true;
+ }
}
// InputEventReceiver to listen for touch input outside of caption bounds
@@ -548,9 +583,11 @@
relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
boolean dragFromStatusBarAllowed = false;
if (DesktopModeStatus.isProto2Enabled()) {
- // In proto2 any full screen task can be dragged to freeform
- dragFromStatusBarAllowed = relevantDecor.mTaskInfo.getWindowingMode()
- == WINDOWING_MODE_FULLSCREEN;
+ // In proto2 any full screen or multi-window task can be dragged to
+ // freeform.
+ final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
+ dragFromStatusBarAllowed = windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_MULTI_WINDOW;
}
if (dragFromStatusBarAllowed && relevantDecor.checkTouchEventInHandle(ev)) {
@@ -707,8 +744,7 @@
@Nullable
private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isSplitScreenVisible()) {
+ if (mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible()) {
// We can't look at focused task here as only one task will have focus.
return getSplitScreenDecor(ev);
} else {
@@ -719,9 +755,9 @@
@Nullable
private DesktopModeWindowDecoration getSplitScreenDecor(MotionEvent ev) {
ActivityManager.RunningTaskInfo topOrLeftTask =
- mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+ mSplitScreenController.getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
ActivityManager.RunningTaskInfo bottomOrRightTask =
- mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
if (topOrLeftTask != null && topOrLeftTask.getConfiguration()
.windowConfiguration.getBounds().contains((int) ev.getX(), (int) ev.getY())) {
return mWindowDecorByTaskId.get(topOrLeftTask.taskId);
@@ -773,8 +809,8 @@
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
- if (mSplitScreenController.isPresent()
- && mSplitScreenController.get().isTaskRootOrStageRoot(taskInfo.taskId)) {
+ if (mSplitScreenController != null
+ && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
return false;
}
return DesktopModeStatus.isProto2Enabled()
@@ -804,6 +840,7 @@
mMainChoreographer,
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
+ windowDecoration.createResizeVeil();
final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
windowDecoration, taskInfo);
@@ -834,7 +871,6 @@
mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
mTransactionFactory);
} else {
- windowDecoration.createResizeVeil();
return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
mTransitions);
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 ce11b26..e3cb8af 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
@@ -178,7 +178,7 @@
mRelayoutParams.reset();
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = windowDecorLayoutId;
- mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
+ mRelayoutParams.mCaptionHeightId = getCaptionHeightId();
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
@@ -235,6 +235,7 @@
mHandler,
mChoreographer,
mDisplay.getDisplayId(),
+ mRelayoutParams.mCornerRadius,
mDecorationContainerSurface,
mDragPositioningCallback);
}
@@ -294,23 +295,37 @@
}
/**
- * Fade in the resize veil
+ * Show the resize veil.
*/
- void showResizeVeil(Rect taskBounds) {
+ public void showResizeVeil(Rect taskBounds) {
mResizeVeil.showVeil(mTaskSurface, taskBounds);
}
/**
+ * Show the resize veil.
+ */
+ public void showResizeVeil(SurfaceControl.Transaction tx, Rect taskBounds) {
+ mResizeVeil.showVeil(tx, mTaskSurface, taskBounds, false /* fadeIn */);
+ }
+
+ /**
* Set new bounds for the resize veil
*/
- void updateResizeVeil(Rect newBounds) {
+ public void updateResizeVeil(Rect newBounds) {
mResizeVeil.updateResizeVeil(newBounds);
}
/**
+ * Set new bounds for the resize veil
+ */
+ public void updateResizeVeil(SurfaceControl.Transaction tx, Rect newBounds) {
+ mResizeVeil.updateResizeVeil(tx, newBounds);
+ }
+
+ /**
* Fade the resize veil out.
*/
- void hideResizeVeil() {
+ public void hideResizeVeil() {
mResizeVeil.hideVeil();
}
@@ -479,6 +494,11 @@
}
}
+ @Override
+ int getCaptionHeightId() {
+ return R.dimen.freeform_decor_caption_height;
+ }
+
/**
* Add transition to mTransitionsPausingRelayout
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 58644b2..da26898 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -24,6 +24,9 @@
import android.graphics.PointF;
import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.Nullable;
/**
* A detector for touch inputs that differentiates between drag and click inputs. It receives a flow
@@ -54,14 +57,24 @@
*
* @return the result returned by {@link #mEventHandler}, or the result when
* {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
- */
+ */
boolean onMotionEvent(MotionEvent ev) {
+ return onMotionEvent(null /* view */, ev);
+ }
+
+ /**
+ * The receiver of the {@link MotionEvent} flow.
+ *
+ * @return the result returned by {@link #mEventHandler}, or the result when
+ * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
+ */
+ boolean onMotionEvent(View v, MotionEvent ev) {
final boolean isTouchScreen =
(ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
if (!isTouchScreen) {
// Only touches generate noisy moves, so mouse/trackpad events don't need to filtered
// to take the slop threshold into consideration.
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
@@ -69,7 +82,7 @@
float rawX = ev.getRawX(0);
float rawY = ev.getRawY(0);
mInputDownPoint.set(rawX, rawY);
- mResultOfDownAction = mEventHandler.handleMotionEvent(ev);
+ mResultOfDownAction = mEventHandler.handleMotionEvent(v, ev);
return mResultOfDownAction;
}
case ACTION_MOVE: {
@@ -87,7 +100,7 @@
// The event handler should only be notified about 'move' events if a drag has been
// detected.
if (mIsDragEvent) {
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
} else {
return mResultOfDownAction;
}
@@ -95,10 +108,10 @@
case ACTION_UP:
case ACTION_CANCEL: {
resetState();
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
default:
- return mEventHandler.handleMotionEvent(ev);
+ return mEventHandler.handleMotionEvent(v, ev);
}
}
@@ -114,6 +127,6 @@
}
interface MotionEventHandler {
- boolean handleMotionEvent(MotionEvent ev);
+ boolean handleMotionEvent(@Nullable View v, MotionEvent ev);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 287d861..68b63e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -42,6 +42,7 @@
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.SurfaceControl;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManagerGlobal;
@@ -55,7 +56,7 @@
*/
class DragResizeInputListener implements AutoCloseable {
private static final String TAG = "DragResizeInputListener";
-
+ private static final float TOP_CORNER_PADDING = 1.5f;
private final IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession();
private final Handler mHandler;
private final Choreographer mChoreographer;
@@ -73,6 +74,7 @@
private int mTaskHeight;
private int mResizeHandleThickness;
private int mCornerSize;
+ private int mTaskCornerRadius;
private Rect mLeftTopCornerBounds;
private Rect mRightTopCornerBounds;
@@ -87,12 +89,14 @@
Handler handler,
Choreographer choreographer,
int displayId,
+ int taskCornerRadius,
SurfaceControl decorationSurface,
DragPositioningCallback callback) {
mInputManager = context.getSystemService(InputManager.class);
mHandler = handler;
mChoreographer = choreographer;
mDisplayId = displayId;
+ mTaskCornerRadius = taskCornerRadius;
mDecorationSurface = decorationSurface;
// Use a fake window as the backing surface is a container layer and we don't want to create
// a buffer layer for it so we can't use ViewRootImpl.
@@ -303,7 +307,7 @@
}
@Override
- public boolean handleMotionEvent(MotionEvent e) {
+ public boolean handleMotionEvent(View v, MotionEvent e) {
boolean result = false;
// Check if this is a touch event vs mouse event.
// Touch events are tracked in four corners. Other events are tracked in resize edges.
@@ -383,19 +387,67 @@
@DragPositioningCallback.CtrlType
private int calculateResizeHandlesCtrlType(float x, float y) {
int ctrlType = 0;
- if (x < 0) {
+ // mTaskCornerRadius is only used in comparing with corner regions. Comparisons with
+ // sides will use the bounds specified in setGeometry and not go into task bounds.
+ if (x < mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_LEFT;
}
- if (x > mTaskWidth) {
+ if (x > mTaskWidth - mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_RIGHT;
}
- if (y < 0) {
+ if (y < mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_TOP;
}
- if (y > mTaskHeight) {
+ if (y > mTaskHeight - mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_BOTTOM;
}
- return ctrlType;
+ return checkDistanceFromCenter(ctrlType, x, y);
+ }
+
+ // If corner input is not within appropriate distance of corner radius, do not use it.
+ // If input is not on a corner or is within valid distance, return ctrlType.
+ @DragPositioningCallback.CtrlType
+ private int checkDistanceFromCenter(@DragPositioningCallback.CtrlType int ctrlType,
+ float x, float y) {
+ int centerX;
+ int centerY;
+
+ // Determine center of rounded corner circle; this is simply the corner if radius is 0.
+ switch (ctrlType) {
+ case CTRL_TYPE_LEFT | CTRL_TYPE_TOP: {
+ centerX = mTaskCornerRadius;
+ centerY = mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM: {
+ centerX = mTaskCornerRadius;
+ centerY = mTaskHeight - mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_RIGHT | CTRL_TYPE_TOP: {
+ centerX = mTaskWidth - mTaskCornerRadius;
+ centerY = mTaskCornerRadius;
+ break;
+ }
+ case CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM: {
+ centerX = mTaskWidth - mTaskCornerRadius;
+ centerY = mTaskHeight - mTaskCornerRadius;
+ break;
+ }
+ default: {
+ return ctrlType;
+ }
+ }
+ double distanceFromCenter = Math.hypot(x - centerX, y - centerY);
+
+ // TODO(b/286461778): Remove this when input in top corner gap no longer goes to header
+ float cornerPadding = (ctrlType & CTRL_TYPE_TOP) != 0 ? TOP_CORNER_PADDING : 1;
+
+ if (distanceFromCenter < mTaskCornerRadius + mResizeHandleThickness * cornerPadding
+ && distanceFromCenter >= mTaskCornerRadius) {
+ return ctrlType;
+ }
+ return 0;
}
@DragPositioningCallback.CtrlType
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 8277109..bfce72b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -102,11 +102,17 @@
}
/**
- * Animate veil's alpha to 1, fading it in.
+ * Shows the veil surface/view.
+ *
+ * @param t the transaction to apply in sync with the veil draw
+ * @param parentSurface the surface that the veil should be a child of
+ * @param taskBounds the bounds of the task that owns the veil
+ * @param fadeIn if true, the veil will fade-in with an animation, if false, it will be shown
+ * immediately
*/
- public void showVeil(SurfaceControl parentSurface, Rect taskBounds) {
+ public void showVeil(SurfaceControl.Transaction t, SurfaceControl parentSurface,
+ Rect taskBounds, boolean fadeIn) {
// Parent surface can change, ensure it is up to date.
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
if (!parentSurface.equals(mParentSurface)) {
t.reparent(mVeilSurface, parentSurface);
mParentSurface = parentSurface;
@@ -115,22 +121,36 @@
int backgroundColorId = getBackgroundColorId();
mViewHost.getView().setBackgroundColor(mContext.getColor(backgroundColorId));
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(0f, 1f);
- animator.setDuration(RESIZE_ALPHA_DURATION);
- animator.addUpdateListener(animation -> {
- t.setAlpha(mVeilSurface, animator.getAnimatedFraction());
- t.apply();
- });
-
relayout(taskBounds, t);
- t.show(mVeilSurface)
- .addTransactionCommittedListener(mContext.getMainExecutor(), () -> animator.start())
- .setAlpha(mVeilSurface, 0);
+ if (fadeIn) {
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(0f, 1f);
+ animator.setDuration(RESIZE_ALPHA_DURATION);
+ animator.addUpdateListener(animation -> {
+ t.setAlpha(mVeilSurface, animator.getAnimatedFraction());
+ t.apply();
+ });
+
+ t.show(mVeilSurface)
+ .addTransactionCommittedListener(
+ mContext.getMainExecutor(), () -> animator.start())
+ .setAlpha(mVeilSurface, 0);
+ } else {
+ // Show the veil immediately at full opacity.
+ t.show(mVeilSurface).setAlpha(mVeilSurface, 1);
+ }
mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
/**
+ * Animate veil's alpha to 1, fading it in.
+ */
+ public void showVeil(SurfaceControl parentSurface, Rect taskBounds) {
+ SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ showVeil(t, parentSurface, taskBounds, true /* fadeIn */);
+ }
+
+ /**
* Update veil bounds to match bounds changes.
* @param newBounds bounds to update veil to.
*/
@@ -147,6 +167,16 @@
*/
public void updateResizeVeil(Rect newBounds) {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ updateResizeVeil(t, newBounds);
+ }
+
+ /**
+ * Calls relayout to update task and veil bounds.
+ *
+ * @param t a transaction to be applied in sync with the veil draw.
+ * @param newBounds bounds to update veil to.
+ */
+ public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) {
relayout(newBounds, t);
mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 9f03d9a..ae1a3d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -22,6 +22,7 @@
import android.window.TransitionInfo;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreenController;
/**
* The interface used by some {@link com.android.wm.shell.ShellTaskOrganizer.TaskListener} to help
@@ -39,6 +40,11 @@
void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
/**
+ * Sets the {@link SplitScreenController} if available.
+ */
+ void setSplitScreenController(SplitScreenController splitScreenController);
+
+ /**
* Creates a window decoration for the given task. Can be {@code null} for Fullscreen tasks but
* not Freeform ones.
*
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 67ec6cf..4407f2e 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
@@ -267,6 +267,7 @@
.setColor(mTaskSurface, mTmpColor)
.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
+ .setShadowRadius(mTaskSurface, shadowRadius)
.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
@@ -304,6 +305,10 @@
}
}
+ int getCaptionHeightId() {
+ return Resources.ID_NULL;
+ }
+
/**
* Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or
* registers {@link #mOnDisplaysChangedListener} if it doesn't.
@@ -418,6 +423,21 @@
mSurfaceControlTransactionSupplier);
}
+ /**
+ * Adds caption inset source to a WCT
+ */
+ public void addCaptionInset(WindowContainerTransaction wct) {
+ final int captionHeightId = getCaptionHeightId();
+ if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL) {
+ return;
+ }
+
+ final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
+ final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
+ wct.addInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, WindowInsets.Type.captionBar(),
+ captionInsets);
+ }
+
static class RelayoutParams {
RunningTaskInfo mRunningTaskInfo;
int mLayoutResId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
index 76c80f7..d293cf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
@@ -1,32 +1,35 @@
package com.android.wm.shell.windowdecor.viewholder
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
import android.graphics.Color
import android.view.View
import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
+
/**
* Encapsulates the root [View] of a window decoration and its children to facilitate looking up
* children (via findViewById) and updating to the latest data from [RunningTaskInfo].
*/
internal abstract class DesktopModeWindowDecorationViewHolder(rootView: View) {
- val context: Context = rootView.context
+ val context: Context = rootView.context
- /**
- * A signal to the view holder that new data is available and that the views should be updated
- * to reflect it.
- */
- abstract fun bindData(taskInfo: RunningTaskInfo)
+ /**
+ * A signal to the view holder that new data is available and that the views should be updated to
+ * reflect it.
+ */
+ abstract fun bindData(taskInfo: RunningTaskInfo)
- /**
- * Whether the caption items should use the 'light' color variant so that there's good contrast
- * with the caption background color.
- */
- protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
- return if (Color.alpha(taskInfo.taskDescription.statusBarColor) != 0) {
- Color.valueOf(taskInfo.taskDescription.statusBarColor).luminance() < 0.5
- } else {
- taskInfo.taskDescription.statusBarAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0
- }
+ /**
+ * Whether the caption items should use the 'light' color variant so that there's good contrast
+ * with the caption background color.
+ */
+ protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
+ return if (Color.alpha(taskInfo.taskDescription.statusBarColor) != 0 &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ Color.valueOf(taskInfo.taskDescription.statusBarColor).luminance() < 0.5
+ } else {
+ taskInfo.taskDescription.statusBarAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0
}
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 6178156..3000008 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -23,16 +23,15 @@
import android.tools.device.flicker.legacy.FlickerTest
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.flicker.legacy.IFlickerTestData
import com.android.wm.shell.flicker.BaseTest
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.appWindowKeepVisible
import com.android.wm.shell.flicker.layerKeepVisible
import org.junit.After
import org.junit.Assume
import org.junit.Before
-import org.junit.runners.Parameterized
abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
@@ -58,12 +57,13 @@
cmdHelper = CommandsHelper.getInstance(instrumentation)
Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
letterboxStyle = mapLetterboxStyle()
+ resetLetterboxStyle()
setLetterboxEducationEnabled(false)
}
@After
fun after() {
- resetLetterboxEducationEnabled()
+ resetLetterboxStyle()
}
private fun mapLetterboxStyle(): HashMap<String, String> {
@@ -87,9 +87,8 @@
return letterboxStyle
}
- private fun resetLetterboxEducationEnabled() {
- val enabled = getLetterboxStyle().getValue("Is education enabled")
- cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ private fun resetLetterboxStyle() {
+ cmdHelper.executeShellCommand("wm reset-letterbox-style")
}
private fun setLetterboxEducationEnabled(enabled: Boolean) {
@@ -126,25 +125,21 @@
flicker.appWindowIsVisibleAtEnd(letterboxApp)
}
+ fun assertLetterboxAppKeepVisible() {
+ assertLetterboxAppWindowKeepVisible()
+ assertLetterboxAppLayerKeepVisible()
+ }
+
fun assertAppLetterboxedAtEnd() =
flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
fun assertAppLetterboxedAtStart() =
flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+ fun assertAppStaysLetterboxed() =
+ flicker.assertLayers { isVisible(ComponentNameMatcher.LETTERBOX) }
+
fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return FlickerTestFactory.rotationTests()
- }
- }
+ fun assertLetterboxAppWindowKeepVisible() = flicker.appWindowKeepVisible(letterboxApp)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index c2141a3..3d83455 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
import androidx.test.filters.RequiresDevice
import org.junit.Test
import org.junit.runner.RunWith
@@ -90,4 +91,18 @@
.isInvisible(ComponentNameMatcher.ROTATION)
}
}
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.rotationTests()
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
new file mode 100644
index 0000000..c3355ed
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.wm.shell.flicker.appcompat
+
+import android.platform.test.annotations.Postsubmit
+import android.tools.common.Rotation
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.helpers.WindowUtils
+
+import androidx.test.filters.RequiresDevice
+import org.junit.Test
+
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a fixed portrait letterboxed app in landscape and repositioning to the right.
+ *
+ * To run this test: `atest WMShellFlickerTests:RepositionFixedPortraitAppTest`
+ * Actions:
+ * ```
+ * Launch a fixed portrait app in landscape to letterbox app
+ * Double tap to the right to reposition app and wait for app to move
+ * ```
+ *
+ * Notes:
+ * ```
+ * Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [BaseTest]
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class RepositionFixedPortraitAppTest(flicker: FlickerTest) : BaseAppCompat(flicker) {
+
+ val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation).bounds
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ setStartRotation()
+ letterboxApp.launchViaIntent(wmHelper)
+ }
+ transitions {
+ letterboxApp.repositionHorizontally(displayBounds, true)
+ letterboxApp.waitForAppToMoveHorizontallyTo(wmHelper, displayBounds, true)
+ }
+ teardown {
+ letterboxApp.repositionHorizontally(displayBounds, false)
+ letterboxApp.exit(wmHelper)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+
+ @Postsubmit
+ @Test
+ fun letterboxAppLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+ @Postsubmit
+ @Test
+ fun appStaysLetterboxed() = assertAppStaysLetterboxed()
+
+ @Postsubmit
+ @Test
+ fun appKeepVisible() = assertLetterboxAppKeepVisible()
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_90)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index b0e1a42..c2057d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -20,6 +20,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.helpers.WindowUtils
import androidx.test.filters.RequiresDevice
import org.junit.Test
@@ -88,4 +89,18 @@
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) }
}
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.rotationTests()
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
new file mode 100644
index 0000000..f7ce870
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
@@ -0,0 +1,200 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.app.Instrumentation
+import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.helpers.WindowUtils
+import android.tools.device.traces.parsers.toFlickerComponent
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
+import org.junit.Assume
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app via auto-enter property when navigating to home from split screen.
+ *
+ * To run this test: `atest WMShellFlickerTests:AutoEnterPipOnGoToHomeTest`
+ *
+ * Actions:
+ * ```
+ * Launch an app in full screen
+ * Select "Auto-enter PiP" radio button
+ * Open all apps and drag another app icon to enter split screen
+ * Press Home button or swipe up to go Home and put [pipApp] in pip mode
+ * ```
+ *
+ * Notes:
+ * ```
+ * 1. All assertions are inherited from [EnterPipTest]
+ * 2. Part of the test setup occurs automatically via
+ * [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) :
+ AutoEnterPipOnGoToHomeTest(flicker) {
+ private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
+ /** Second app used to enter split screen mode */
+ protected val secondAppForSplitScreen = getSplitScreenApp(instrumentation)
+ fun getSplitScreenApp(instrumentation: Instrumentation): StandardAppHelper =
+ SimpleAppHelper(
+ instrumentation,
+ ActivityOptions.SplitScreen.Primary.LABEL,
+ ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
+ )
+
+ /** Defines the transition used to run the test */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ secondAppForSplitScreen.launchViaIntent(wmHelper)
+ pipApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ enterSplitScreen()
+ // wait until split screen is established
+ wmHelper
+ .StateSyncBuilder()
+ .withWindowSurfaceAppeared(pipApp)
+ .withWindowSurfaceAppeared(secondAppForSplitScreen)
+ .withSplitDividerVisible()
+ .waitForAndVerify()
+ pipApp.enableAutoEnterForPipActivity()
+ }
+ teardown {
+ // close gracefully so that onActivityUnpinned() can be called before force exit
+ pipApp.closePipWindow(wmHelper)
+ pipApp.exit(wmHelper)
+ secondAppForSplitScreen.exit(wmHelper)
+ }
+ transitions { tapl.goHome() }
+ }
+
+ // TODO(b/285400227) merge the code in a common utility - this is copied from SplitScreenUtils
+ private val TIMEOUT_MS = 3_000L
+ private val overviewSnapshotSelector: BySelector
+ get() = By.res(LAUNCHER_UI_PACKAGE_NAME, "snapshot")
+ private fun enterSplitScreen() {
+ // Note: The initial split position in landscape is different between tablet and phone.
+ // In landscape, tablet will let the first app split to right side, and phone will
+ // split to left side.
+ if (tapl.isTablet) {
+ // TAPL's currentTask on tablet is sometimes not what we expected if the overview
+ // contains more than 3 task views. We need to use uiautomator directly to find the
+ // second task to split.
+ tapl.workspace.switchToOverview().overviewActions.clickSplit()
+ val snapshots = tapl.device.wait(Until.findObjects(overviewSnapshotSelector),
+ TIMEOUT_MS)
+ if (snapshots == null || snapshots.size < 1) {
+ error("Fail to find a overview snapshot to split.")
+ }
+
+ // Find the second task in the upper right corner in split select mode by sorting
+ // 'left' in descending order and 'top' in ascending order.
+ snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
+ t2.getVisibleBounds().left - t1.getVisibleBounds().left
+ }
+ snapshots.sortWith { t1: UiObject2, t2: UiObject2 ->
+ t1.getVisibleBounds().top - t2.getVisibleBounds().top
+ }
+ snapshots[0].click()
+ } else {
+ tapl.workspace
+ .switchToOverview()
+ .currentTask
+ .tapMenu()
+ .tapSplitMenuItem()
+ .currentTask
+ .open()
+ }
+ SystemClock.sleep(TIMEOUT_MS)
+ }
+
+ @Presubmit
+ @Test
+ override fun pipOverlayLayerAppearThenDisappear() {
+ // when entering from split screen we use alpha animation, without overlay
+ }
+
+ @Presubmit
+ @Test
+ override fun pipLayerOrOverlayRemainInsideVisibleBounds() {
+ // when entering from split screen we use alpha animation, without overlay
+ }
+
+ @Presubmit
+ @Test
+ override fun pipLayerReduces() {
+ // when entering from split screen we use alpha animation, so there is no size change
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipLayerReduces()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipAppLayerAlwaysVisible() {
+ // pip layer in gesture nav will disappear during transition with alpha animation
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipAppLayerAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipWindowRemainInsideVisibleBounds() {
+ if (tapl.isTablet) {
+ flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+ } else {
+ // on phones home does not rotate in landscape, PiP enters back to portrait
+ // orientation so use display bounds from that orientation for assertion
+ flicker.assertWmVisibleRegion(pipApp) { coversAtMost(portraitDisplayBounds) }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+ supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index ef7bedf..b95732e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -53,7 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
+open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { tapl.goHome() }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
index 95121de..cdbdb85 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
@@ -62,7 +62,7 @@
*/
@Presubmit
@Test
- fun pipWindowRemainInsideVisibleBounds() {
+ open fun pipWindowRemainInsideVisibleBounds() {
flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
index 9da5ab6..145c8f0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -37,6 +37,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
@@ -51,6 +52,7 @@
public class DividerViewTest extends ShellTestCase {
private @Mock SplitWindowManager.ParentContainerCallbacks mCallbacks;
private @Mock SplitLayout.SplitLayoutHandler mSplitLayoutHandler;
+ private @Mock DisplayController mDisplayController;
private @Mock DisplayImeController mDisplayImeController;
private @Mock ShellTaskOrganizer mTaskOrganizer;
private SplitLayout mSplitLayout;
@@ -62,8 +64,8 @@
MockitoAnnotations.initMocks(this);
Configuration configuration = getConfiguration();
mSplitLayout = new SplitLayout("TestSplitLayout", mContext, configuration,
- mSplitLayoutHandler, mCallbacks, mDisplayImeController, mTaskOrganizer,
- SplitLayout.PARALLAX_NONE);
+ mSplitLayoutHandler, mCallbacks, mDisplayController, mDisplayImeController,
+ mTaskOrganizer, SplitLayout.PARALLAX_NONE);
SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
mContext,
configuration, mCallbacks);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 3d77948..443cea2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -26,6 +26,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
@@ -41,6 +42,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
@@ -57,6 +59,7 @@
public class SplitLayoutTests extends ShellTestCase {
@Mock SplitLayout.SplitLayoutHandler mSplitLayoutHandler;
@Mock SplitWindowManager.ParentContainerCallbacks mCallbacks;
+ @Mock DisplayController mDisplayController;
@Mock DisplayImeController mDisplayImeController;
@Mock ShellTaskOrganizer mTaskOrganizer;
@Mock WindowContainerTransaction mWct;
@@ -72,6 +75,7 @@
getConfiguration(),
mSplitLayoutHandler,
mCallbacks,
+ mDisplayController,
mDisplayImeController,
mTaskOrganizer,
SplitLayout.PARALLAX_NONE));
@@ -100,6 +104,10 @@
// Verify updateConfiguration returns true if the density changed.
config.densityDpi = 123;
assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
+
+ // Verify updateConfiguration checks the current DisplayLayout
+ verify(mDisplayController, times(5)) // init * 1 + updateConfiguration * 4
+ .getDisplayLayout(anyInt());
}
@Test
@@ -168,6 +176,14 @@
verify(mWct).setSmallestScreenWidthDp(eq(task2.token), anyInt());
}
+ @Test
+ public void testRoateTo_checksDisplayLayout() {
+ mSplitLayout.rotateTo(90);
+
+ verify(mDisplayController, times(2)) // init * 1 + rotateTo * 1
+ .getDisplayLayout(anyInt());
+ }
+
private void waitDividerFlingFinished() {
verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(),
mRunnableCaptor.capture());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 17c0463..3fe78ef 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -129,6 +129,18 @@
}
@Test
+ fun addListener_notifiesStashed() {
+ repo.setStashed(DEFAULT_DISPLAY, true)
+ val listener = TestVisibilityListener()
+ val executor = TestShellExecutor()
+ repo.addVisibleTasksListener(listener, executor)
+ executor.flushAll()
+
+ assertThat(listener.stashedOnDefaultDisplay).isTrue()
+ assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1)
+ }
+
+ @Test
fun addListener_tasksOnDifferentDisplay_doesNotNotify() {
repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true)
val listener = TestVisibilityListener()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index dba21b8..1477cf7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -89,6 +89,8 @@
@Mock lateinit var transitions: Transitions
@Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
@Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
+ @Mock lateinit var mToggleResizeDesktopTaskTransitionHandler:
+ ToggleResizeDesktopTaskTransitionHandler
@Mock lateinit var launchAdjacentController: LaunchAdjacentController
private lateinit var mockitoSession: StaticMockitoSession
@@ -129,6 +131,7 @@
transitions,
enterDesktopTransitionHandler,
exitDesktopTransitionHandler,
+ mToggleResizeDesktopTaskTransitionHandler,
desktopModeTaskRepository,
launchAdjacentController,
shellExecutor
@@ -270,8 +273,9 @@
}
@Test
- fun moveToDesktop() {
+ fun moveToDesktop_displayFullscreen_windowingModeSetToFreeform() {
val task = setUpFullscreenTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
controller.moveToDesktop(task)
val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
@@ -279,6 +283,16 @@
}
@Test
+ fun moveToDesktop_displayFreeform_windowingModeSetToUndefined() {
+ val task = setUpFullscreenTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
+ controller.moveToDesktop(task)
+ val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
fun moveToDesktop_nonExistentTask_doesNothing() {
controller.moveToDesktop(999)
verifyWCTNotExecuted()
@@ -325,12 +339,23 @@
}
@Test
- fun moveToFullscreen() {
+ fun moveToFullscreen_displayFullscreen_windowingModeSetToUndefined() {
val task = setUpFreeformTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
controller.moveToFullscreen(task)
val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
- .isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
+ fun moveToFullscreen_displayFreeform_windowingModeSetToFullscreen() {
+ val task = setUpFreeformTask()
+ task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
+ controller.moveToFullscreen(task)
+ val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FULLSCREEN)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
index 425bbf0..1379aed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
@@ -106,21 +106,21 @@
sExpectedDefaultSizes = new HashMap<>();
sExpectedMinSizes = new HashMap<>();
- sExpectedMaxSizes.put(16f / 9, new Size(1000, 562));
- sExpectedDefaultSizes.put(16f / 9, new Size(600, 337));
- sExpectedMinSizes.put(16f / 9, new Size(499, 281));
+ sExpectedMaxSizes.put(16f / 9, new Size(1000, 563));
+ sExpectedDefaultSizes.put(16f / 9, new Size(600, 338));
+ sExpectedMinSizes.put(16f / 9, new Size(501, 282));
sExpectedMaxSizes.put(4f / 3, new Size(892, 669));
sExpectedDefaultSizes.put(4f / 3, new Size(535, 401));
- sExpectedMinSizes.put(4f / 3, new Size(445, 334));
+ sExpectedMinSizes.put(4f / 3, new Size(447, 335));
sExpectedMaxSizes.put(3f / 4, new Size(669, 892));
sExpectedDefaultSizes.put(3f / 4, new Size(401, 535));
- sExpectedMinSizes.put(3f / 4, new Size(334, 445));
+ sExpectedMinSizes.put(3f / 4, new Size(335, 447));
sExpectedMaxSizes.put(9f / 16, new Size(562, 999));
sExpectedDefaultSizes.put(9f / 16, new Size(337, 599));
- sExpectedMinSizes.put(9f / 16, new Size(281, 499));
+ sExpectedMinSizes.put(9f / 16, new Size(281, 500));
}
private void forEveryTestCaseCheck(Map<Float, Size> expectedSizes,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
index 68cb57c..b1befc4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
@@ -41,6 +41,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
/** Tests for {@link MainStage} */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -61,7 +63,7 @@
MockitoAnnotations.initMocks(this);
mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider);
+ mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
index 3b42a48..549bd3f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
@@ -46,6 +46,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.util.Optional;
+
/** Tests for {@link SideStage} */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -66,7 +68,7 @@
MockitoAnnotations.initMocks(this);
mRootTask = new TestRunningTaskInfoBuilder().build();
mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider);
+ mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
mSideStage.onTaskAppeared(mRootTask, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 9810350..e8a1e91 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -72,6 +72,7 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.sysui.ShellSharedConstants;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -104,6 +105,7 @@
@Mock StageCoordinator mStageCoordinator;
@Mock RecentTasksController mRecentTasks;
@Mock LaunchAdjacentController mLaunchAdjacentController;
+ @Mock WindowDecorViewModel mWindowDecorViewModel;
@Captor ArgumentCaptor<Intent> mIntentCaptor;
private ShellController mShellController;
@@ -119,8 +121,8 @@
mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue,
mRootTDAOrganizer, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mDragAndDropController, mTransitions, mTransactionPool,
- mIconProvider, mRecentTasks, mLaunchAdjacentController, mMainExecutor,
- mStageCoordinator));
+ mIconProvider, mRecentTasks, mLaunchAdjacentController, mWindowDecorViewModel,
+ mMainExecutor, mStageCoordinator));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index ff6f59d..a3009a5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -38,6 +38,7 @@
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import java.util.Optional;
@@ -76,12 +77,14 @@
DisplayController displayController, DisplayImeController imeController,
DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
- ShellExecutor mainExecutor, Optional<RecentTasksController> recentTasks,
- LaunchAdjacentController launchAdjacentController) {
+ ShellExecutor mainExecutor,
+ Optional<RecentTasksController> recentTasks,
+ LaunchAdjacentController launchAdjacentController,
+ Optional<WindowDecorViewModel> windowDecorViewModel) {
super(context, displayId, syncQueue, taskOrganizer, mainStage,
sideStage, displayController, imeController, insetsController, splitLayout,
transitions, transactionPool, mainExecutor, recentTasks,
- launchAdjacentController);
+ launchAdjacentController, windowDecorViewModel);
// Prepare root task for testing.
mRootTask = new TestRunningTaskInfoBuilder().build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 0095f65..b00a60c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -77,6 +77,7 @@
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -101,6 +102,7 @@
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
@Mock private IconProvider mIconProvider;
+ @Mock private WindowDecorViewModel mWindowDecorViewModel;
@Mock private ShellExecutor mMainExecutor;
@Mock private LaunchAdjacentController mLaunchAdjacentController;
private SplitLayout mSplitLayout;
@@ -123,17 +125,17 @@
mSplitLayout = SplitTestUtils.createMockSplitLayout();
mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider));
+ mIconProvider, Optional.of(mWindowDecorViewModel)));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider));
+ mIconProvider, Optional.of(mWindowDecorViewModel)));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
mTransactionPool, mMainExecutor, Optional.empty(),
- mLaunchAdjacentController);
+ mLaunchAdjacentController, Optional.empty());
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 91ae1ef..e59d09c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -133,7 +133,7 @@
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
- mMainExecutor, Optional.empty(), mLaunchAdjacentController));
+ mMainExecutor, Optional.empty(), mLaunchAdjacentController, Optional.empty()));
mDividerLeash = new SurfaceControl.Builder(mSurfaceSession).setName("fakeDivider").build();
when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
@@ -162,7 +162,7 @@
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
verify(mMainStage).reparentTopTask(eq(wct));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
@@ -180,7 +180,7 @@
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
}
@@ -192,7 +192,7 @@
mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
- eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+ eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 1a1bebd..df1e2e1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -43,6 +43,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
/**
* Tests for {@link StageTaskListener}
* Build/Install/Run:
@@ -71,6 +74,8 @@
private SyncTransactionQueue mSyncQueue;
@Mock
private IconProvider mIconProvider;
+ @Mock
+ private WindowDecorViewModel mWindowDecorViewModel;
@Captor
private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
private SurfaceSession mSurfaceSession = new SurfaceSession();
@@ -89,7 +94,8 @@
mCallbacks,
mSyncQueue,
mSurfaceSession,
- mIconProvider);
+ mIconProvider,
+ Optional.of(mWindowDecorViewModel));
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID;
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession).setName("test").build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
index 81fc843..1b38956 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java
@@ -128,8 +128,8 @@
doReturn(true).when(mTransitions).isRegistered();
}
mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions));
- mTaskViewTaskController = new TaskViewTaskController(mContext, mOrganizer,
- mTaskViewTransitions, mSyncQueue);
+ mTaskViewTaskController = spy(new TaskViewTaskController(mContext, mOrganizer,
+ mTaskViewTransitions, mSyncQueue));
mTaskView = new TaskView(mContext, mTaskViewTaskController);
mTaskView.setListener(mExecutor, mViewListener);
}
@@ -544,4 +544,23 @@
mTaskView.removeTask();
verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController));
}
+
+ @Test
+ public void testOnTaskAppearedWithTaskNotFound() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTaskController.setTaskNotFound();
+ mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash);
+
+ verify(mTaskViewTaskController).cleanUpPendingTask();
+ verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController));
+ }
+
+ @Test
+ public void testOnTaskAppeared_withoutTaskNotFound() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash);
+ verify(mTaskViewTaskController, never()).cleanUpPendingTask();
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 9d56686..0504439 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.taskview;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.google.common.truth.Truth.assertThat;
@@ -25,16 +26,19 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.graphics.Rect;
+import android.os.IBinder;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.transition.Transitions;
@@ -45,6 +49,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -198,4 +205,34 @@
mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
new Rect(0, 0, 100, 100));
}
+
+ @Test
+ public void test_startAnimation_setsTaskNotFound() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ TransitionInfo.Change change = mock(TransitionInfo.Change.class);
+ when(change.getTaskInfo()).thenReturn(mTaskInfo);
+ when(change.getMode()).thenReturn(TRANSIT_OPEN);
+
+ List<TransitionInfo.Change> changes = new ArrayList<>();
+ changes.add(change);
+
+ TransitionInfo info = mock(TransitionInfo.class);
+ when(info.getChanges()).thenReturn(changes);
+
+ mTaskViewTransitions.startTaskView(new WindowContainerTransaction(),
+ mTaskViewTaskController,
+ mock(IBinder.class));
+
+ TaskViewTransitions.PendingTransition pending =
+ mTaskViewTransitions.findPendingOpeningTransition(mTaskViewTaskController);
+
+ mTaskViewTransitions.startAnimation(pending.mClaimed,
+ info,
+ new SurfaceControl.Transaction(),
+ new SurfaceControl.Transaction(),
+ mock(Transitions.TransitionFinishCallback.class));
+
+ verify(mTaskViewTaskController).setTaskNotFound();
+ }
}
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 963632b..ff380e9 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
@@ -51,7 +51,6 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.after;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
@@ -93,7 +92,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.server.testutils.StubTransaction;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.TransitionInfoBuilder;
@@ -105,6 +103,7 @@
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.sysui.ShellSharedConstants;
+import com.android.wm.shell.util.StubTransaction;
import org.junit.Before;
import org.junit.Test;
@@ -703,8 +702,8 @@
createTaskInfo(1, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
final DisplayController displays = createTestDisplayController();
- final @Surface.Rotation int upsideDown = displays
- .getDisplayLayout(DEFAULT_DISPLAY).getUpsideDownRotation();
+ final DisplayLayout displayLayout = displays.getDisplayLayout(DEFAULT_DISPLAY);
+ final @Surface.Rotation int upsideDown = displayLayout.getUpsideDownRotation();
TransitionInfo.Change displayChange = new ChangeBuilder(TRANSIT_CHANGE)
.setFlags(FLAG_IS_DISPLAY).setRotate().build();
@@ -744,7 +743,8 @@
assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
displayChange, noTask, displays));
- // Not seamless if one of rotations is upside-down
+ // Not seamless if the nav bar cares rotation and one of rotations is upside-down.
+ doReturn(false).when(displayLayout).allowSeamlessRotationDespiteNavBarMoving();
displayChange = new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
.setRotate(upsideDown, ROTATION_ANIMATION_UNSPECIFIED).build();
final TransitionInfo seamlessUpsideDown = new TransitionInfoBuilder(TRANSIT_CHANGE)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/StubTransaction.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/StubTransaction.java
new file mode 100644
index 0000000..855f541
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/StubTransaction.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.view.InputWindowHandle;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * Stubbed {@link SurfaceControl.Transaction} class that can be used when unit
+ * testing to avoid calls to native code.
+ *
+ * Note: This is a copy of com.android.server.testutils.StubTransaction
+ */
+public class StubTransaction extends SurfaceControl.Transaction {
+
+ private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>();
+
+ @Override
+ public void apply() {
+ for (Runnable listener : mWindowInfosReportedListeners) {
+ listener.run();
+ }
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void apply(boolean sync) {
+ apply();
+ }
+
+ @Override
+ public SurfaceControl.Transaction setVisibility(SurfaceControl sc, boolean visible) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction show(SurfaceControl sc) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction hide(SurfaceControl sc) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setPosition(SurfaceControl sc, float x, float y) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setBufferSize(SurfaceControl sc,
+ int w, int h) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setLayer(SurfaceControl sc, int z) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo,
+ int z) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setTransparentRegionHint(SurfaceControl sc,
+ Region transparentRegion) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setAlpha(SurfaceControl sc, float alpha) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setInputWindowInfo(SurfaceControl sc,
+ InputWindowHandle handle) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setGeometry(SurfaceControl sc, Rect sourceCrop,
+ Rect destFrame, @Surface.Rotation int orientation) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setMatrix(SurfaceControl sc,
+ float dsdx, float dtdx, float dtdy, float dsdy) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColorTransform(SurfaceControl sc, float[] matrix,
+ float[] translation) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public SurfaceControl.Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction reparent(SurfaceControl sc, SurfaceControl newParent) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColor(SurfaceControl sc, float[] color) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setDisplayFlags(IBinder displayToken, int flags) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setDisplayProjection(IBinder displayToken,
+ int orientation, Rect layerStackRect, Rect displayRect) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setDisplaySize(IBinder displayToken, int width, int height) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setAnimationTransaction() {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setMetadata(SurfaceControl sc, int key, int data) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setMetadata(SurfaceControl sc, int key, Parcel data) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction merge(SurfaceControl.Transaction other) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction remove(SurfaceControl sc) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction addTransactionCommittedListener(Executor executor,
+ SurfaceControl.TransactionCommittedListener listener) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColorSpaceAgnostic(SurfaceControl sc, boolean agnostic) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setFrameRateSelectionPriority(SurfaceControl sc,
+ int priority) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setFrameRate(SurfaceControl sc, float frameRate,
+ int compatibility, int changeFrameRateStrategy) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction unsetColor(SurfaceControl sc) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setFixedTransformHint(SurfaceControl sc,
+ @Surface.Rotation int transformHint) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setBuffer(SurfaceControl sc, GraphicBuffer buffer) {
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public SurfaceControl.Transaction setBuffer(@NonNull SurfaceControl sc,
+ @Nullable HardwareBuffer buffer) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setTrustedOverlay(SurfaceControl sc,
+ boolean isTrustedOverlay) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction addWindowInfosReportedListener(@NonNull Runnable listener) {
+ mWindowInfosReportedListeners.add(listener);
+ return this;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 41bab95..23158ea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -53,7 +53,6 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopTasksController;
-import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -82,7 +81,6 @@
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
@Mock private DisplayLayout mDisplayLayout;
- @Mock private SplitScreenController mSplitScreenController;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private DesktopModeController mDesktopModeController;
@Mock private DesktopTasksController mDesktopTasksController;
@@ -111,7 +109,6 @@
mTransitions,
Optional.of(mDesktopModeController),
Optional.of(mDesktopTasksController),
- Optional.of(mSplitScreenController),
mDesktopModeWindowDecorFactory,
mMockInputMonitorFactory,
mTransactionFactory
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
index 8f84008..3fbab0f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
@@ -55,7 +55,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(eventHandler.handleMotionEvent(any())).thenReturn(true)
+ `when`(eventHandler.handleMotionEvent(any(), any())).thenReturn(true)
dragDetector = DragDetector(eventHandler)
dragDetector.setTouchSlop(SLOP)
@@ -72,13 +72,13 @@
@Test
fun testNoMove_passesDownAndUp() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -86,12 +86,12 @@
@Test
fun testMoveInSlop_touch_passesDownAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -99,12 +99,12 @@
val newX = X + SLOP - 1
assertFalse(
dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y)))
- verify(eventHandler, never()).handleMotionEvent(argThat {
+ verify(eventHandler, never()).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -112,13 +112,13 @@
@Test
fun testMoveInSlop_mouse_passesDownMoveAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
@@ -126,14 +126,14 @@
val newX = X + SLOP - 1
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_UP, newX, Y, isTouch = false)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_MOUSE
})
@@ -141,25 +141,25 @@
@Test
fun testMoveBeyondSlop_passesDownMoveAndUp() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
val newX = X + SLOP + 1
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_UP, newX, Y)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_UP && it.x == newX && it.y == Y &&
it.source == InputDevice.SOURCE_TOUCHSCREEN
})
@@ -167,12 +167,12 @@
@Test
fun testPassesHoverEnter() {
- `when`(eventHandler.handleMotionEvent(argThat {
+ `when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_HOVER_ENTER
})).thenReturn(false)
assertFalse(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_ENTER)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_ENTER && it.x == X && it.y == Y
})
}
@@ -180,7 +180,7 @@
@Test
fun testPassesHoverMove() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_MOVE)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_MOVE && it.x == X && it.y == Y
})
}
@@ -188,7 +188,7 @@
@Test
fun testPassesHoverExit() {
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_EXIT)))
- verify(eventHandler).handleMotionEvent(argThat {
+ verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_EXIT && it.x == X && it.y == Y
})
}
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 f941e95..7fc1c99 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
@@ -57,7 +57,6 @@
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
@@ -411,15 +410,17 @@
verify(additionalWindowSurfaceBuilder).build();
verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 0, 0);
final int width = WindowDecoration.loadDimensionPixelSize(
- mContext.getResources(), mCaptionMenuWidthId);
+ windowDecor.mDecorWindowContext.getResources(), mCaptionMenuWidthId);
final int height = WindowDecoration.loadDimensionPixelSize(
- mContext.getResources(), mRelayoutParams.mCaptionHeightId);
+ windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
- final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ final int shadowRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
mCaptionMenuShadowRadiusId);
verify(mMockSurfaceControlAddWindowT)
.setShadowRadius(additionalWindowSurface, shadowRadius);
- final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ final int cornerRadius = WindowDecoration.loadDimensionPixelSize(
+ windowDecor.mDecorWindowContext.getResources(),
mCaptionMenuCornerRadiusId);
verify(mMockSurfaceControlAddWindowT)
.setCornerRadius(additionalWindowSurface, cornerRadius);
@@ -514,8 +515,7 @@
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
- return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
- mMockDisplayController, mMockShellTaskOrganizer,
+ return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
taskInfo, testSurface,
new MockObjectSupplier<>(mMockSurfaceControlBuilders,
() -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index b796585..d237cc2 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -18,6 +18,9 @@
#include <SkImage.h>
#include <include/gpu/ganesh/SkImageGanesh.h>
+#include <include/gpu/GrBackendSurfaceMutableState.h>
+#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/GrBackendSurface.h>
#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include "utils/PaintUtils.h"
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index 0f8a85d..cec0ee7 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -86,6 +86,16 @@
return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
}
+jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) {
+ Gainmap* gainmap = new Gainmap();
+ gainmap->incStrong(0);
+ if (sourcePtr) {
+ Gainmap* src = fromJava(sourcePtr);
+ gainmap->info = src->info;
+ }
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
+}
+
static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
@@ -237,6 +247,7 @@
static const JNINativeMethod gGainmapMethods[] = {
{"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
{"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
+ {"nCreateCopy", "(J)J", (void*)Gainmap_createCopy},
{"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
{"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
{"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index ff7c89a..d7ac501 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -21,6 +21,8 @@
#include "GrBackendSurface.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
+#include "SkCanvas.h"
+#include "SkCanvasAndroid.h"
#include "SkClipStack.h"
#include "SkRect.h"
#include "SkM44.h"
@@ -35,7 +37,7 @@
namespace skiapipeline {
static void setScissor(int viewportHeight, const SkIRect& clip) {
- SkASSERT(!clip.isEmpty());
+ LOG_FATAL_IF(clip.isEmpty(), "empty scissor clip");
// transform to Y-flipped GL space, and prevent negatives
GLint y = viewportHeight - clip.fBottom;
GLint height = (viewportHeight - clip.fTop) - y;
@@ -43,7 +45,7 @@
}
static void GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) {
- GrBackendRenderTarget renderTarget = canvas->topLayerBackendRenderTarget();
+ GrBackendRenderTarget renderTarget = skgpu::ganesh::TopLayerBackendRenderTarget(canvas);
GrGLFramebufferInfo fboInfo;
LOG_ALWAYS_FATAL_IF(!renderTarget.getGLFramebufferInfo(&fboInfo),
"getGLFrameBufferInfo failed");
@@ -83,7 +85,7 @@
SkISize fboSize;
GetFboDetails(canvas, &fboID, &fboSize);
- SkIRect surfaceBounds = canvas->topLayerBounds();
+ SkIRect surfaceBounds = skgpu::ganesh::TopLayerBounds(canvas);
SkIRect clipBounds = canvas->getDeviceClipBounds();
SkM44 mat4(canvas->getLocalToDevice());
SkRegion clipRegion;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 16b35ff..a5518eb 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -405,8 +405,17 @@
// If the previous frame was dropped we don't need to hold onto it, so
// just keep using the previous frame's structure instead
- if (!wasSkipped(mCurrentFrameInfo)) {
+ if (wasSkipped(mCurrentFrameInfo)) {
+ // Use the oldest skipped frame in case we skip more than a single frame
+ if (!mSkippedFrameInfo) {
+ mSkippedFrameInfo.emplace();
+ mSkippedFrameInfo->vsyncId =
+ mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
+ mSkippedFrameInfo->startTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
+ }
+ } else {
mCurrentFrameInfo = mJankTracker.startFrame();
+ mSkippedFrameInfo.reset();
}
mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
@@ -602,10 +611,18 @@
if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
const auto inputEventId =
static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId));
- native_window_set_frame_timeline_info(
- mNativeSurface->getNativeWindow(), frameCompleteNr, vsyncId, inputEventId,
- mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime),
- solelyTextureViewUpdates);
+ const ANativeWindowFrameTimelineInfo ftl = {
+ .frameNumber = frameCompleteNr,
+ .frameTimelineVsyncId = vsyncId,
+ .inputEventId = inputEventId,
+ .startTimeNanos = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime),
+ .useForRefreshRateSelection = solelyTextureViewUpdates,
+ .skippedFrameVsyncId = mSkippedFrameInfo ? mSkippedFrameInfo->vsyncId
+ : UiFrameInfoBuilder::INVALID_VSYNC_ID,
+ .skippedFrameStartTimeNanos =
+ mSkippedFrameInfo ? mSkippedFrameInfo->startTime : 0,
+ };
+ native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), ftl);
}
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 5219b57..32ac5af 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -366,6 +366,12 @@
ColorMode mColorMode = ColorMode::Default;
float mTargetSdrHdrRatio = 1.f;
+
+ struct SkippedFrameInfo {
+ int64_t vsyncId;
+ int64_t startTime;
+ };
+ std::optional<SkippedFrameInfo> mSkippedFrameInfo;
};
} /* namespace renderthread */
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 32680da..b7c97208 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -359,6 +359,51 @@
codec to use a previously created {@linkplain #createPersistentInputSurface persistent input
surface} by calling {@link #setInputSurface}.
+ <h4 id=EncoderProfiles><a name="EncoderProfiles"></a>Encoder Profiles</h4>
+ <p>
+ When using an encoder, it is recommended to set the desired codec {@link MediaFormat#KEY_PROFILE
+ profile} during {@link #configure configure()}. (This is only meaningful for
+ {@link MediaFormat#KEY_MIME media formats} for which profiles are defined.)
+ <p>
+ If a profile is not specified during {@code configure}, the encoder will choose a profile for the
+ session based on the available information. We will call this value the <i>default profile</i>.
+ The selection of the default profile is device specific and may not be deterministic
+ (could be ad hoc or even experimental). The encoder may choose a default profile that is not
+ suitable for the intended encoding session, which may result in the encoder ultimately rejecting
+ the session.
+ <p>
+ The encoder may reject the encoding session if the configured (or default if unspecified) profile
+ does not support the codec input (mainly the {@link MediaFormat#KEY_COLOR_FORMAT color format} for
+ video/image codecs, or the {@link MediaFormat#KEY_PCM_ENCODING sample encoding} and the {@link
+ MediaFormat#KEY_CHANNEL_COUNT number of channels} for audio codecs, but also possibly
+ {@link MediaFormat#KEY_WIDTH width}, {@link MediaFormat#KEY_HEIGHT height},
+ {@link MediaFormat#KEY_FRAME_RATE frame rate}, {@link MediaFormat#KEY_BIT_RATE bitrate} or
+ {@link MediaFormat#KEY_SAMPLE_RATE sample rate}.)
+ Alternatively, the encoder may choose to (but is not required to) convert the input to support the
+ selected (or default) profile - or adjust the chosen profile based on the presumed or detected
+ input format - to ensure a successful encoding session. <b>Note</b>: Converting the input to match
+ an incompatible profile will in most cases result in decreased codec performance.
+ <p>
+ To ensure backward compatibility, the following guarantees are provided by Android:
+ <ul>
+ <li>The default video encoder profile always supports 8-bit YUV 4:2:0 color format ({@link
+ CodecCapabilities#COLOR_FormatYUV420Flexible COLOR_FormatYUV420Flexible} and equivalent
+ {@link CodecCapabilities#colorFormats supported formats}) for both Surface and ByteBuffer modes.
+ <li>The default video encoder profile always supports the default 8-bit RGBA color format in
+ Surface mode even if no such formats are enumerated in the {@link CodecCapabilities#colorFormats
+ supported formats}.
+ </ul>
+ <p class=note>
+ <b>Note</b>: the accepted profile can be queried through the {@link #getOutputFormat output
+ format} of the encoder after {@code configure} to allow applications to set up their
+ codec input to a format supported by the encoder profile.
+ <p>
+ <b>Implication:</b>
+ <ul>
+ <li>Applications that want to encode 4:2:2, 4:4:4, 10+ bit or HDR video input <b>MUST</b> configure
+ a suitable profile for encoders.
+ </ul>
+
<h4 id=CSD><a name="CSD"></a>Codec-specific Data</h4>
<p>
Some formats, notably AAC audio and MPEG4, H.264 and H.265 video formats require the actual data
@@ -4888,8 +4933,12 @@
* Called when an output frame has rendered on the output surface.
* <p>
* <strong>Note:</strong> This callback is for informational purposes only: to get precise
- * render timing samples, and can be significantly delayed and batched. Some frames may have
- * been rendered even if there was no callback generated.
+ * render timing samples, and can be significantly delayed and batched. Starting with
+ * Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, a callback will always
+ * be received for each rendered frame providing the MediaCodec is still in the executing
+ * state when the callback is dispatched. Prior to Android
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, some frames may have been
+ * rendered even if there was no callback generated.
*
* @param codec the MediaCodec instance
* @param presentationTimeUs the presentation time (media time) of the frame rendered.
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index b1b7d40..46db777 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1136,11 +1136,14 @@
* may fail if other parameters are not compatible with the desired
* profile or if the desired profile is not supported, but it may also
* fail silently (where the encoder ends up using a different, compatible profile.)
+ * <p>
+ * It is recommended that the profile is set for all encoders. For more information, see
+ * the <i>Encoder Profiles</i> section of the {@link MediaCodec} API reference.
* <p class="note">
* <strong>Note:</strong> Codecs are free to use all the available
* coding tools at the specified profile, but may ultimately choose to not do so.
* <p class="note">
- * <strong>Note:</strong> When configuring video encoders, profile must be
+ * <strong>Note:</strong> When configuring video encoders, profile (if set) must be
* set together with {@link #KEY_LEVEL level}.
*
* @see MediaCodecInfo.CodecCapabilities#profileLevels
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 3394dd0..e8adfaf 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -134,9 +134,11 @@
/**
* @hide
- * @param audioAttributes to identify AudioProductStrategy with
- * @return legacy stream type associated with matched AudioProductStrategy
- * Defaults to STREAM_MUSIC if no match is found, or if matches is STREAM_DEFAULT
+ * @param audioAttributes to identify {@link AudioProductStrategy} with
+ * @return legacy stream type associated with matched {@link AudioProductStrategy}. If no
+ * strategy found or found {@link AudioProductStrategy} does not have associated
+ * legacy stream (i.e. associated with {@link AudioSystem#STREAM_DEFAULT}) defaults
+ * to {@link AudioSystem#STREAM_MUSIC}
*/
public static int getLegacyStreamTypeForStrategyWithAudioAttributes(
@NonNull AudioAttributes audioAttributes) {
@@ -147,9 +149,9 @@
int streamType = productStrategy.getLegacyStreamTypeForAudioAttributes(
audioAttributes);
if (streamType == AudioSystem.STREAM_DEFAULT) {
- Log.w(TAG, "Attributes " + audioAttributes.toString() + " ported by strategy "
- + productStrategy.getId() + " has no stream type associated, "
- + "DO NOT USE STREAM TO CONTROL THE VOLUME");
+ Log.w(TAG, "Attributes " + audioAttributes + " supported by strategy "
+ + productStrategy.getId() + " have no associated stream type, "
+ + "therefore falling back to STREAM_MUSIC");
return AudioSystem.STREAM_MUSIC;
}
if (streamType < AudioSystem.getNumStreamTypes()) {
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 1b04f18..feb914f 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1468,6 +1468,10 @@
return (int)Result::INVALID_STATE;
}
+ if (mDemuxClient != NULL) {
+ mDemuxClient->setFrontendDataSourceById(feId);
+ }
+
mSharedFeId = feId;
return (int)Result::SUCCESS;
}
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 727b766..7d277c9 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -30,7 +30,7 @@
<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="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>
+ <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>이 휴대전화에서 이 정보에 액세스하도록 허용"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
<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>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 5398579..7a6fad4 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -20,7 +20,7 @@
<string name="app_label">Companion Device Manager</string>
<!-- Title of the device association confirmation dialog. -->
- <string name="confirmation_title">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to access <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong>?</string>
+ <string name="confirmation_title">Allow the app <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to access <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong>?</string>
<!-- ================= DEVICE_PROFILE_WATCH and null profile ================= -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 2dafbcb..a78509d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -66,8 +66,9 @@
)
val originName: String? = when (requestInfo?.type) {
- RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin
- RequestInfo.TYPE_GET -> requestInfo.getCredentialRequest?.origin
+ RequestInfo.TYPE_CREATE -> processHttpsOrigin(
+ requestInfo.createCredentialRequest?.origin)
+ RequestInfo.TYPE_GET -> processHttpsOrigin(requestInfo.getCredentialRequest?.origin)
else -> null
}
@@ -247,6 +248,9 @@
}
companion object {
+ private const val HTTPS = "https://"
+ private const val FORWARD_SLASH = "/"
+
fun sendCancellationCode(
cancelCode: Int,
requestToken: IBinder?,
@@ -266,5 +270,17 @@
CancelUiRequest::class.java
)
}
+
+ /** Removes "https://", and the trailing slash if present for an https request. */
+ private fun processHttpsOrigin(origin: String?): String? {
+ var processed = origin
+ if (processed?.startsWith(HTTPS) == true) { // Removes "https://"
+ processed = processed.substring(HTTPS.length)
+ if (processed?.endsWith(FORWARD_SLASH) == true) { // Removes the trailing slash
+ processed = processed.substring(0, processed.length - 1)
+ }
+ }
+ return processed
+ }
}
}
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 3545179..778bdfe 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Program geïnstalleer."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil jy hierdie program installeer?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil jy hierdie program opdateer?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Dateer hierdie app vanaf <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> op?\n\nHierdie app kry gewoonlik opdaterings vanaf <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou foon kry. Appfunksie kan verander."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Dateer hierdie app vanaf <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> op?\n\nHierdie app kry gewoonlik opdaterings vanaf <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. As jy vanaf ’n ander bron opdateer, kan jy in die toekoms dalk opdaterings vanaf enige bron op jou foon kry. Appfunksie kan verander."</string>
<string name="install_failed" msgid="5777824004474125469">"Program nie geïnstalleer nie."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die installering van die pakket is geblokkeer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Program is nie geïnstalleer nie omdat pakket met \'n bestaande pakket bots."</string>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 3dab467c..dcc6a92 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"መተግበሪያ ተጭኗል።"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ይህን መተግበሪያ መጫን ይፈልጋሉ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ይህን መተግበሪያ ማዘመን ይፈልጋሉ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ይህ መተግበሪያ ከ<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ይዘምን?\n\nይህ መተግበሪያ በመደበኛነት ዝማኔዎችን ከ<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ይቀበላል። ከተለየ ምንጭ በማዘመን በስልክዎ ላይ ካለ ማንኛውም ምንጭ የወደፊት ዝማኔዎችን ሊቀበሉ ይችላሉ። የመተግበሪያ ተግባራዊነት ሊለወጥ ይችላል።"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ይህ መተግበሪያ ከ<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ይዘምን?\n\nይህ መተግበሪያ በመደበኛነት ዝማኔዎችን ከ<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ይቀበላል። ከተለየ ምንጭ በማዘመን በስልክዎ ላይ ካለ ማንኛውም ምንጭ የወደፊት ዝማኔዎችን ሊቀበሉ ይችላሉ። የመተግበሪያ ተግባራዊነት ሊለወጥ ይችላል።"</string>
<string name="install_failed" msgid="5777824004474125469">"መተግበሪያ አልተጫነም።"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ጥቅሉ እንዳይጫን ታግዷል።"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"እንደ ጥቅል ያልተጫነ መተግበሪያ ከነባር ጥቅል ጋር ይጋጫል።"</string>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index 170c1fc..57e0206 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"تم تثبيت التطبيق."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"هل تريد تثبيت هذا التطبيق؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"هل تريد تحديث هذا التطبيق؟"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"هل تريد تحديث هذا التطبيق من خلال \"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>\"؟\n\nيتلقّى هذا التطبيق التحديثات عادةً من \"<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>\". من خلال إجراء التحديث من مصدر مختلف، قد تتلقّى تحديثات في المستقبل من أي مصدر على هاتفك. قد تتغير وظائف التطبيق."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"هل تريد تحديث هذا التطبيق من خلال \"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>\"؟\n\nيتلقّى هذا التطبيق التحديثات عادةً من \"<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>\". من خلال إجراء التحديث من مصدر مختلف، قد تتلقّى تحديثات في المستقبل من أي مصدر على هاتفك. قد تتغير وظائف التطبيق."</string>
<string name="install_failed" msgid="5777824004474125469">"التطبيق ليس مثبتًا."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"تم حظر تثبيت الحزمة."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"لم يتم تثبيت التطبيق لأن حزمة التثبيت تتعارض مع حزمة حالية."</string>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index 37f6c13..a7957f5 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"এপ্ ইনষ্টল কৰা হ’ল।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপুনি এই এপ্টো ইনষ্টল কৰিবলৈ বিচাৰেনে?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপুনি এই এপ্টো আপডে’ট কৰিবলৈ বিচাৰেনে?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"এই এপ্টো <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ৰ পৰা আপডে’ট কৰিবনে?\n\nএই এপ্টোৱে সাধাৰণতে <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ ফ’নত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"এই এপ্টো <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ৰ পৰা আপডে’ট কৰিবনে?\n\nএই এপ্টোৱে সাধাৰণতে <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ৰ পৰা আপডে’ট লাভ কৰে। অন্য এটা উৎসৰ পৰা আপডে’ট কৰি আপুনি যিকোনো উৎসৰ পৰা আপোনাৰ ফ’নত অনাগত আপডে’টসমূহ পাব পাৰে। এপৰ কাৰ্যক্ষমতা সলনি হ’ব পাৰে।"</string>
<string name="install_failed" msgid="5777824004474125469">"এপ্ ইনষ্টল কৰা হোৱা নাই।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"পেকেজটোৰ ইনষ্টল অৱৰোধ কৰা হৈছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"এপ্টো ইনষ্টল কৰিব পৰা নগ\'ল কাৰণ ইয়াৰ সৈতে আগৰে পৰা থকা এটা পেকেজৰ সংঘাত হৈছে।"</string>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index ae7b2fc..ee6ace8 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Tətbiq quraşdırılıb."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu tətbiqi quraşdırmaq istəyirsiniz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu tətbiqi güncəlləmək istəyirsiniz?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu tətbiq <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> mənbəyindən güncəllənsin?\n\nBu tətbiq adətən <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> mənbəyindən güncəllənmələr qəbul edir. Fərqli mənbədən güncəllədikdə telefonda istənilən mənbədən gələcəkdə güncəllənmələr qəbul edə bilərsiniz. Tətbiq funksionallığı dəyişə bilər."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu tətbiq <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> mənbəyindən güncəllənsin?\n\nBu tətbiq adətən <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> mənbəyindən güncəllənmələr qəbul edir. Fərqli mənbədən güncəllədikdə telefonda istənilən mənbədən gələcəkdə güncəllənmələr qəbul edə bilərsiniz. Tətbiq funksionallığı dəyişə bilər."</string>
<string name="install_failed" msgid="5777824004474125469">"Tətbiq quraşdırılmayıb."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin quraşdırılması blok edildi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Bu paketin mövcud paket ilə ziddiyətinə görə tətbiq quraşdırılmadı."</string>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index 2b0fa82..e267132 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite da instalirate ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite da ažurirate ovu aplikaciju?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite da ažurirate ovu aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija se obično ažurira iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na telefonu. Funkcije aplikacije mogu da se promene."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite da ažurirate ovu aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija se obično ažurira iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako ažurirate iz drugog izvora, možete da primate buduća ažuriranja iz bilo kog izvora na telefonu. Funkcije aplikacije mogu da se promene."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer je paket neusaglašen sa postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index d18e009..70d2995 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Праграма ўсталявана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Усталяваць гэту праграму?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Абнавіць гэту праграму?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Абнавіць праграму ад <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗвычайна гэтая праграма атрымлівае абнаўленні ад <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Пры абнаўленні з іншай крыніцы вы, магчыма, будзеце атрымліваць будучыя абнаўленні з любой крыніцы на тэлефоне. Функцыі праграмы могуць змяніцца."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Абнавіць праграму ад <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗвычайна гэтая праграма атрымлівае абнаўленні ад <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Пры абнаўленні з іншай крыніцы вы, магчыма, будзеце атрымліваць будучыя абнаўленні з любой крыніцы на тэлефоне. Функцыі праграмы могуць змяніцца."</string>
<string name="install_failed" msgid="5777824004474125469">"Праграма не ўсталявана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Усталяванне пакета заблакіравана."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Праграма не ўсталявана, таму што пакет канфліктуе з існуючым пакетам."</string>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index 6dc927f..b3f9629 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Приложението бе инсталирано."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Искате ли да инсталирате това приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Искате ли да актуализирате това приложение?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Да се актуализира ли това приложение от <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nТо обикновено получава актуализации от <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако инсталирате актуализация от друг източник, може да получавате бъдещи актуализации от който и да е източник на телефона си. Функционалността на приложението може да се промени."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Да се актуализира ли това приложение от <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nТо обикновено получава актуализации от <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако инсталирате актуализация от друг източник, може да получавате бъдещи актуализации от който и да е източник на телефона си. Функционалността на приложението може да се промени."</string>
<string name="install_failed" msgid="5777824004474125469">"Приложението не бе инсталирано."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирането на пакета бе блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложението не бе инсталирано, тъй като пакетът е в конфликт със съществуващ пакет."</string>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 5b5c6dc..5be4f7a 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"অ্যাপটি ইনস্টল করা হয়ে গেছে।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"আপনি কি এই অ্যাপটি ইনস্টল করতে চান?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"আপনি কি এই অ্যাপটি আপডেট করতে চান?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> থেকে এই অ্যাপ আপডেট করবেন?\n\nএই অ্যাপ সাধারণত <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> থেকে আপডেট পায়। অন্য কোনও সোর্স থেকে আপডেট করলে, আপনার ফোনে ভবিষ্যতে যেকোনও সোর্স থেকে আপডেট পেতে পারেন। অ্যাপের কার্যকারিতা পরিবর্তন হতে পারে।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> থেকে এই অ্যাপ আপডেট করবেন?\n\nএই অ্যাপ সাধারণত <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> থেকে আপডেট পায়। অন্য কোনও সোর্স থেকে আপডেট করলে, আপনার ফোনে ভবিষ্যতে যেকোনও সোর্স থেকে আপডেট পেতে পারেন। অ্যাপের কার্যকারিতা পরিবর্তন হতে পারে।"</string>
<string name="install_failed" msgid="5777824004474125469">"অ্যাপটি ইনস্টল করা হয়নি।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ইনস্টল হওয়া থেকে প্যাকেজটিকে ব্লক করা হয়েছে।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"আগে থেকেই থাকা একটি প্যাকেজের সাথে প্যাকেজটির সমস্যা সৃষ্টি হওয়ায় অ্যাপটি ইনস্টল করা যায়নি।"</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index e728937..2bf85c7 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Ažurirati aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate iz drugog izvora, možda ćete primati buduća ažuriranja iz bilo kojeg izvora na telefonu. Funkcionalnost aplikacije se može promijeniti."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Ažurirati aplikaciju iz izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja iz izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate iz drugog izvora, možda ćete primati buduća ažuriranja iz bilo kojeg izvora na telefonu. Funkcionalnost aplikacije se može promijeniti."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje ovog paketa je blokirano."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija nije instalirana jer paket nije usaglašen s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 8b0d1a8..6df1490 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"S\'ha instal·lat l\'aplicació."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vols instal·lar aquesta aplicació?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vols actualitzar aquesta aplicació?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vols actualitzar l\'aplicació des de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAquesta aplicació sol rebre actualitzacions a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si l\'actualitzes des d\'una font diferent, pot ser que en el futur rebis actualitzacions des de qualsevol font del teu telèfon. És possible que la funcionalitat de l\'aplicació canviï."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vols actualitzar l\'aplicació des de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAquesta aplicació sol rebre actualitzacions a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si l\'actualitzes des d\'una font diferent, pot ser que en el futur rebis actualitzacions des de qualsevol font del teu telèfon. És possible que la funcionalitat de l\'aplicació canviï."</string>
<string name="install_failed" msgid="5777824004474125469">"No s\'ha instal·lat l\'aplicació."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"El paquet s\'ha bloquejat perquè no es pugui instal·lar."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'aplicació no s\'ha instal·lat perquè el paquet entra en conflicte amb un d\'existent."</string>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index c96d27e..f602bf6 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikace je nainstalována."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete tuto aplikaci nainstalovat?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete tuto aplikaci aktualizovat?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Aktualizovat tuto aplikaci ze zdroje <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTato aplikace obvykle dostává aktualizace ze zdroje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Pokud ji aktualizujete z jiného zdroje, budete v budoucnu do telefonu moci dostávat aktualizace z libovolného zdroje. Funkčnost aplikace se může změnit."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Aktualizovat tuto aplikaci ze zdroje <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTato aplikace obvykle dostává aktualizace ze zdroje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Pokud ji aktualizujete z jiného zdroje, budete v budoucnu do telefonu moci dostávat aktualizace z libovolného zdroje. Funkčnost aplikace se může změnit."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikaci nelze nainstalovat."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalace balíčku byla zablokována."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikaci nelze nainstalovat, protože balíček je v konfliktu se stávajícím balíčkem."</string>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index d8759d4..04007bf 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installeret."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du opdatere denne app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vil du opdatere denne app fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne app plejer at modtage opdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Appfunktionaliteten kan ændre sig."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vil du opdatere denne app fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne app plejer at modtage opdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Appfunktionaliteten kan ændre sig."</string>
<string name="install_failed" msgid="5777824004474125469">"Appen blev ikke installeret."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken blev forhindret i at blive installeret."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen blev ikke installeret, da pakken er i strid med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index bb55708..48f7cda 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App wurde installiert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Möchtest du diese App installieren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Möchtest du diese App aktualisieren?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Diese App mit einem Update von <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> aktualisieren?\n\nSie erhält normalerweise Updates von <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Wenn du ein Update von einer anderen Quelle verwendest, erhältst du möglicherweise zukünftige Updates von beliebigen Quellen auf deinem Smartphone. Die Funktionalität der App kann sich ändern."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Diese App mit einem Update von <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> aktualisieren?\n\nSie erhält normalerweise Updates von <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Wenn du ein Update von einer anderen Quelle verwendest, erhältst du möglicherweise zukünftige Updates von beliebigen Quellen auf deinem Smartphone. Die Funktionalität der App kann sich ändern."</string>
<string name="install_failed" msgid="5777824004474125469">"App wurde nicht installiert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Die Installation des Pakets wurde blockiert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Die App wurde nicht installiert, da das Paket in Konflikt mit einem bestehenden Paket steht."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 9721a19..54e282c 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Η εφαρμογή εγκαταστάθηκε."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτήν την εφαρμογή;"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτήν την εφαρμογή;"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Να ενημερωθεί αυτή η εφαρμογή από <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>;\n\nΗ συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Να ενημερωθεί αυτή η εφαρμογή από <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>;\n\nΗ συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει."</string>
<string name="install_failed" msgid="5777824004474125469">"Η εφαρμογή δεν εγκαταστάθηκε."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Η εγκατάσταση του πακέτου αποκλείστηκε."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Η εφαρμογή δεν εγκαταστάθηκε, επειδή το πακέτο είναι σε διένεξη με κάποιο υπάρχον πακέτο."</string>
diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml
index 543dbf6..6927c3e 100644
--- a/packages/PackageInstaller/res/values-en-rAU/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rCA/strings.xml b/packages/PackageInstaller/res/values-en-rCA/strings.xml
index f2457f2..03c0c27 100644
--- a/packages/PackageInstaller/res/values-en-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rCA/strings.xml
@@ -26,7 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="738046584021528374">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="3056133099508550163">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml
index 543dbf6..6927c3e 100644
--- a/packages/PackageInstaller/res/values-en-rGB/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml
index 543dbf6..6927c3e 100644
--- a/packages/PackageInstaller/res/values-en-rIN/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-en-rXC/strings.xml b/packages/PackageInstaller/res/values-en-rXC/strings.xml
index a674c20..c36b3e9 100644
--- a/packages/PackageInstaller/res/values-en-rXC/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rXC/strings.xml
@@ -26,7 +26,9 @@
<string name="install_done" msgid="5987363587661783896">"App installed."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Do you want to install this app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Do you want to update this app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="738046584021528374">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="3056133099508550163">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change."</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update this app from <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change."</string>
<string name="install_failed" msgid="5777824004474125469">"App not installed."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"The package was blocked from being installed."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App not installed as package conflicts with an existing package."</string>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index eb3abe9..c41dfb6 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Se instaló la app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Deseas instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Deseas actualizar esta app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"¿Quieres actualizar esta app a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEn general, esta suele recibir actualizaciones de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Por ende, podría verse afectada la funcionalidad de la app."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"¿Quieres actualizar esta app a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEn general, esta suele recibir actualizaciones de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Por ende, podría verse afectada la funcionalidad de la app."</string>
<string name="install_failed" msgid="5777824004474125469">"No se instaló la app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se bloqueó el paquete para impedir la instalación."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"No se instaló la app debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 9005718..7fdf346 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplicación instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"¿Quieres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"¿Quieres actualizar esta aplicación?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"¿Actualizar esta aplicación a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEsta aplicación normalmente recibe actualizaciones a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si la actualizas usando otra fuente, puede que recibas futuras actualizaciones a través de cualquier fuente en tu teléfono. La funcionalidad de la aplicación puede cambiar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"¿Actualizar esta aplicación a través de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEsta aplicación normalmente recibe actualizaciones a través de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si la actualizas usando otra fuente, puede que recibas futuras actualizaciones a través de cualquier fuente en tu teléfono. La funcionalidad de la aplicación puede cambiar."</string>
<string name="install_failed" msgid="5777824004474125469">"No se ha instalado la aplicación."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Se ha bloqueado la instalación del paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"La aplicación no se ha instalado debido a un conflicto con un paquete."</string>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index cf488a9..7f3c4a5 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Rakendus on installitud."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Kas soovite selle rakenduse installida?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Kas soovite seda rakendust värskendada?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Kas värskendada seda rakendust allikast <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nSee rakendus saab tavaliselt värskendusi allikast <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Muust allikast värskendamise korral võite edaspidi saada telefonis värskendusi mis tahes allikast. Rakenduse funktsioonid võivad muutuda."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Kas värskendada seda rakendust allikast <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nSee rakendus saab tavaliselt värskendusi allikast <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Muust allikast värskendamise korral võite edaspidi saada telefonis värskendusi mis tahes allikast. Rakenduse funktsioonid võivad muutuda."</string>
<string name="install_failed" msgid="5777824004474125469">"Rakendus pole installitud."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketi installimine blokeeriti."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Rakendust ei installitud, kuna pakett on olemasoleva paketiga vastuolus."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index 9dadbed..e446d47 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Instalatu da aplikazioa."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Aplikazioa instalatu nahi duzu?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Aplikazioa eguneratu nahi duzu?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Aplikazioa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> zerbitzutik eguneratu nahi duzu?\n\nAplikazioak <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> zerbitzutik jaso ohi ditu eguneratzeak. Beste iturburu batetik eguneratuz gero, baliteke aurrerantzeko eguneratzeak telefonoko edozein iturburutatik jasotzea. Baliteke aplikazioaren funtzioak aldatzea."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Aplikazioa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> zerbitzutik eguneratu nahi duzu?\n\nAplikazioak <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> zerbitzutik jaso ohi ditu eguneratzeak. Beste iturburu batetik eguneratuz gero, baliteke aurrerantzeko eguneratzeak telefonoko edozein iturburutatik jasotzea. Baliteke aplikazioaren funtzioak aldatzea."</string>
<string name="install_failed" msgid="5777824004474125469">"Ez da instalatu aplikazioa."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketea instalatzeko aukera blokeatu egin da."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Ez da instalatu aplikazioa, gatazka bat sortu delako lehendik dagoen pakete batekin."</string>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index 73b070d..b2d3d76 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"برنامه نصب شد."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"میخواهید این برنامه را نصب کنید؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"میخواهید این برنامه را بهروزرسانی کنید؟"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"این برنامه ازطریق <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> بهروز شود؟\n\nاین برنامه معمولاً بهروزرسانیها را از <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> دریافت میکند. با بهروزرسانی از منبعی متفاوت، ممکن است بهروزرسانیهای بعدی را از هر منبعی در تلفنتان دریافت کنید. قابلیتهای برنامه ممکن است تغییر کند."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"این برنامه ازطریق <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> بهروز شود؟\n\nاین برنامه معمولاً بهروزرسانیها را از <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> دریافت میکند. با بهروزرسانی از منبعی متفاوت، ممکن است بهروزرسانیهای بعدی را از هر منبعی در تلفنتان دریافت کنید. قابلیتهای برنامه ممکن است تغییر کند."</string>
<string name="install_failed" msgid="5777824004474125469">"برنامه نصب نشد."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"از نصب شدن بسته جلوگیری شد."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"برنامه نصب نشد چون بسته با بسته موجود تداخل دارد."</string>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index ee8910b..6c63e4b 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Sovellus on asennettu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Haluatko asentaa tämän sovelluksen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Haluatko päivittää tämän sovelluksen?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Voiko <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> päivittää sovelluksen?\n\nTämän sovelluksen päivitykset tarjoaa yleensä <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kun päivität uudesta lähteestä, tulevat päivitykset voivat tulla mistä tahansa puhelimella olevasta lähteestä. Sovelluksen toiminnot voivat muuttua."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Voiko <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> päivittää sovelluksen?\n\nTämän sovelluksen päivitykset tarjoaa yleensä <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kun päivität uudesta lähteestä, tulevat päivitykset voivat tulla mistä tahansa puhelimella olevasta lähteestä. Sovelluksen toiminnot voivat muuttua."</string>
<string name="install_failed" msgid="5777824004474125469">"Sovellusta ei asennettu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin asennus estettiin."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Sovellusta ei asennettu, koska paketti on ristiriidassa nykyisen paketin kanssa."</string>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index b971c35..9b82fd4 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette application?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette application?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Mettre à jour cette application à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nCette application reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut en être modifié."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Mettre à jour cette application à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nCette application reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. En effectuant une mise à jour à partir d\'une source différente, vous pourriez recevoir des mises à jour futures à partir de n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut en être modifié."</string>
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du paquet a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le paquet entre en conflit avec un paquet existant."</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 08d37d1..2fc5e53 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Application installée."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Mettre à jour cette appli à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ?\n\nCette appli reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application est susceptible de changer."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Mettre à jour cette appli à partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ?\n\nCette appli reçoit normalement des mises à jour de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application est susceptible de changer."</string>
<string name="install_failed" msgid="5777824004474125469">"Application non installée."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du package a été bloquée."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le package est en conflit avec un package déjà présent."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index d6cbf60..39bab7a 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Instalouse a aplicación."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Queres instalar esta aplicación?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Queres actualizar esta aplicación?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Queres actualizar esta aplicación desde <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs actualizacións desta aplicación adoitan provir de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se actualizas a aplicación desde unha fonte diferente, pode que, a partir de agora, recibas actualizacións de calquera fonte no teléfono. Poderían cambiar as funcións da aplicación."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Queres actualizar esta aplicación desde <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAs actualizacións desta aplicación adoitan provir de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se actualizas a aplicación desde unha fonte diferente, pode que, a partir de agora, recibas actualizacións de calquera fonte no teléfono. Poderían cambiar as funcións da aplicación."</string>
<string name="install_failed" msgid="5777824004474125469">"Non se instalou a aplicación"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Bloqueouse a instalación do paquete."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A aplicación non se instalou porque o paquete presenta un conflito cun paquete que xa hai."</string>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index dcaa48f..1793887 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"શું તમે આ ઍપ ઇન્સ્ટૉલ કરવા માગો છો?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"શું તમે આ ઍપ અપડેટ કરવા માગો છો?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"આ ઍપને <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>થી અપડેટ કરવી છે?\n\nઆ ઍપ સામાન્ય રીતે <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ફોન પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતા બદલાઈ શકે છે."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"આ ઍપને <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>થી અપડેટ કરવી છે?\n\nઆ ઍપ સામાન્ય રીતે <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>થી અપડેટ મેળવે છે. અલગ સૉર્સથી અપડેટ કરીને, તમે તમારા ફોન પર કોઈપણ સૉર્સથી ભાવિ અપડેટ મેળવી શકો છો. ઍપની કાર્યક્ષમતા બદલાઈ શકે છે."</string>
<string name="install_failed" msgid="5777824004474125469">"ઍપ્લિકેશન ઇન્સ્ટૉલ કરી નથી."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"પૅકેજને ઇન્સ્ટૉલ થવાથી બ્લૉક કરવામાં આવ્યું હતું."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"પૅકેજનો અસ્તિત્વમાંના પૅકેજ સાથે વિરોધાભાસ હોવાને કારણે ઍપ્લિકેશન ઇન્સ્ટૉલ થઈ નથી."</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index df3353b..cfcec76 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ऐप्लिकेशन इंस्टॉल हो गया."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"क्या आपको यह ऐप्लिकेशन इंस्टॉल करना है?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"क्या आप इस ऐप्लिकेशन को अपडेट करना चाहते हैं?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"क्या इस ऐप्लिकेशन को <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> से अपडेट करना है?\n\nआम तौर पर, इस ऐप्लिकेशन को <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> से अपडेट मिलते हैं. किसी दूसरे सोर्स से अपडेट करने पर, आपको नए अपडेट फ़ोन पर मौजूद किसी भी सोर्स से मिल सकते हैं. इसके साथ ही, ऐप्लिकेशन की मुख्य सुविधाओं और उनके काम करने के तरीके में बदलाव आ सकता है."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"क्या इस ऐप्लिकेशन को <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> से अपडेट करना है?\n\nआम तौर पर, इस ऐप्लिकेशन को <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> से अपडेट मिलते हैं. किसी दूसरे सोर्स से अपडेट करने पर, आपको नए अपडेट फ़ोन पर मौजूद किसी भी सोर्स से मिल सकते हैं. इसके साथ ही, ऐप्लिकेशन की मुख्य सुविधाओं और उनके काम करने के तरीके में बदलाव आ सकता है."</string>
<string name="install_failed" msgid="5777824004474125469">"ऐप्लिकेशन इंस्टॉल नहीं हुआ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पैकेज को इंस्टॉल होने से ब्लॉक किया हुआ है."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ऐप्लिकेशन इंस्टॉल नहीं हुआ क्योंकि पैकेज का किसी मौजूदा पैकेज से विरोध है."</string>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index 74c1fa1..a7621dd 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je instalirana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Želite li instalirati ovu aplikaciju?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Želite li ažurirati ovu aplikaciju?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite li ovu aplikaciju ažurirati s izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja s izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate s nekog drugog izvora, buduća ažuriranja možete primati s bilo kojeg izvora na svojem telefonu. Funkcije aplikacije mogu se promijeniti."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite li ovu aplikaciju ažurirati s izvora <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nOva aplikacija obično prima ažuriranja s izvora <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ako je ažurirate s nekog drugog izvora, buduća ažuriranja možete primati s bilo kojeg izvora na svojem telefonu. Funkcije aplikacije mogu se promijeniti."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija nije instalirana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instaliranje paketa blokirano je."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija koja nije instalirana kao paket u sukobu je s postojećim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index 823c20c..b02b4aa 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Alkalmazás telepítve."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Telepíti ezt az alkalmazást?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Frissíti ezt az alkalmazást?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Frissíti az appot ebből a forrásból: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEz az app általában a következő forrásból kap frissítéseket: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ha másik forrásból frissíti, a későbbiekben bármelyik forrásból kaphat frissítéseket a telefonján. Emiatt megváltozhat az app működése."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Frissíti az appot ebből a forrásból: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEz az app általában a következő forrásból kap frissítéseket: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ha másik forrásból frissíti, a későbbiekben bármelyik forrásból kaphat frissítéseket a telefonján. Emiatt megváltozhat az app működése."</string>
<string name="install_failed" msgid="5777824004474125469">"Az alkalmazás nincs telepítve."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A csomag telepítését letiltotta a rendszer."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A nem csomagként telepített alkalmazás ütközik egy már létező csomaggal."</string>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index 4f56568..48a10e8 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Հավելվածը տեղադրված է:"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Տեղադրե՞լ այս հավելվածը:"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Թարմացնե՞լ այս հավելվածը։"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Թարմացնե՞լ այս հավելվածը <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ից։\n\nՍովորաբար այս հավելվածի թարմացումները ստացվում են <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ից։ Եթե թարմացնեք այլ աղբյուրից, հետագայում կարող եք ձեր հեռախոսում թարմացումներ ստանալ ցանկացած աղբյուրից։ Հավելվածի գործառույթները կարող են փոփոխվել։"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Թարմացնե՞լ այս հավելվածը <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ից։\n\nՍովորաբար այս հավելվածի թարմացումները ստացվում են <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ից։ Եթե թարմացնեք այլ աղբյուրից, հետագայում կարող եք ձեր հեռախոսում թարմացումներ ստանալ ցանկացած աղբյուրից։ Հավելվածի գործառույթները կարող են փոփոխվել։"</string>
<string name="install_failed" msgid="5777824004474125469">"Հավելվածը տեղադրված չէ:"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Փաթեթի տեղադրումն արգելափակվել է:"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Հավելվածը չի տեղադրվել, քանի որ տեղադրման փաթեթն ունի հակասություն առկա փաթեթի հետ:"</string>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index 0758a1d..f204419 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi terinstal."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingin menginstal aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingin mengupdate aplikasi ini?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Update aplikasi ini dari <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAplikasi ini biasanya menerima update dari <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan mengupdate dari sumber yang berbeda, Anda mungkin menerima update berikutnya dari sumber mana pun di ponsel. Fungsi aplikasi mungkin berubah."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Update aplikasi ini dari <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAplikasi ini biasanya menerima update dari <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan mengupdate dari sumber yang berbeda, Anda mungkin menerima update berikutnya dari sumber mana pun di ponsel. Fungsi aplikasi mungkin berubah."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak terinstal."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paket diblokir sehingga tidak dapat diinstal."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikasi tidak diinstal karena paket ini bentrok dengan paket yang sudah ada."</string>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index 6cbb2ee..94dc375 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Forritið er uppsett."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Viltu setja upp þetta forrit?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Viltu uppfæra þetta forrit?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Uppfæra þetta forrit frá <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nÞetta forrit fær venjulega uppfærslur frá <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Með því að uppfæra frá öðrum uppruna gætirðu fengið framtíðaruppfærslur frá hvaða uppruna sem er í símanum. Forritseiginleikar kunna að breytast."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Uppfæra þetta forrit frá <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nÞetta forrit fær venjulega uppfærslur frá <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Með því að uppfæra frá öðrum uppruna gætirðu fengið framtíðaruppfærslur frá hvaða uppruna sem er í símanum. Forritseiginleikar kunna að breytast."</string>
<string name="install_failed" msgid="5777824004474125469">"Forritið er ekki uppsett."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Lokað var á uppsetningu pakkans."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Forritið var ekki sett upp vegna árekstra á milli pakkans og annars pakka."</string>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 323db1d..0f97d54 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App installata."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vuoi installare questa app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vuoi aggiornare questa app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vuoi aggiornare questa app tramite <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nGeneralmente l\'app viene aggiornata tramite <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sul telefono. La funzionalità dell\'app potrebbe cambiare."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vuoi aggiornare questa app tramite <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nGeneralmente l\'app viene aggiornata tramite <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se la aggiorni da un\'origine diversa, in futuro potresti ricevere aggiornamenti da qualsiasi origine sul telefono. La funzionalità dell\'app potrebbe cambiare."</string>
<string name="install_failed" msgid="5777824004474125469">"App non installata."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"È stata bloccata l\'installazione del pacchetto."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App non installata poiché il pacchetto è in conflitto con un pacchetto esistente."</string>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 24beba6..0f0c029 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"האפליקציה הותקנה."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"האם ברצונך להתקין אפליקציה זו?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"האם ברצונך לעדכן אפליקציה זו?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"לקבל את העדכון לאפליקציה הזו מ-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nהאפליקציה הזו בדרך כלל מקבלת עדכונים מ: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלפון. תכונות האפליקציה יכולות להשתנות."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"לקבל את העדכון לאפליקציה הזו מ-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nהאפליקציה הזו בדרך כלל מקבלת עדכונים מ: <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. אם בחרת לעדכן ממקור אחר, יכול להיות שבעתיד יתקבלו עדכונים ממקורות אחרים בטלפון. תכונות האפליקציה יכולות להשתנות."</string>
<string name="install_failed" msgid="5777824004474125469">"האפליקציה לא הותקנה."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"החבילה נחסמה להתקנה."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"האפליקציה לא הותקנה כי החבילה מתנגשת עם חבילה קיימת."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 95b789e..b045ed5 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"アプリをインストールしました。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"このアプリをインストールしますか?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"このアプリを更新しますか?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"このアプリを <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> から更新しますか?\n\nこのアプリは通常、<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> からアップデートを受信しています。別の提供元から更新することにより、お使いのスマートフォンで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"このアプリを <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> から更新しますか?\n\nこのアプリは通常、<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> からアップデートを受信しています。別の提供元から更新することにより、お使いのスマートフォンで今後のアップデートを任意の提供元から受け取ることになります。アプリの機能は変更される場合があります。"</string>
<string name="install_failed" msgid="5777824004474125469">"アプリはインストールされていません。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"パッケージのインストールはブロックされています。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"パッケージが既存のパッケージと競合するため、アプリをインストールできませんでした。"</string>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index 0699f0b..b0b1162 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"აპი დაინსტალირებულია."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"გნებავთ ამ აპის დაყენება?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"გსურთ ამ აპის განახლება?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"გსურთ განაახლოთ ეს აპი <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ისგან?\n\nეს აპი, როგორც წესი, განახლებებს იღებს <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ისგან. აპის სხვა წყაროდან განახლებით შემდგომში განახლებების მიღებას შეძლებთ ნებისმიერი წყაროდან თქვენს ტელეფონზე. აპის ფუნქციები, შესაძლოა, შეიცვალოს."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"გსურთ განაახლოთ ეს აპი <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-ისგან?\n\nეს აპი, როგორც წესი, განახლებებს იღებს <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-ისგან. აპის სხვა წყაროდან განახლებით შემდგომში განახლებების მიღებას შეძლებთ ნებისმიერი წყაროდან თქვენს ტელეფონზე. აპის ფუნქციები, შესაძლოა, შეიცვალოს."</string>
<string name="install_failed" msgid="5777824004474125469">"აპი დაუინსტალირებელია."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ამ პაკეტის ინსტალაცია დაბლოკილია."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"აპი ვერ დაინსტალირდა, რადგან პაკეტი კონფლიქტშია არსებულ პაკეტთან."</string>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index 129267f..2011b80 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Қолданба орнатылды."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бұл қолданбаны орнатқыңыз келе ме?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бұл қолданбаны жаңартқыңыз келе ме?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Бұл қолданба <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> арқылы жаңартылсын ба?\n\nБұл қолданба әдетте <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> көмегімен жаңартылады. Басқа дереккөзден жаңартсаңыз, алдағы жаңартулар телефоныңыздағы кез келген дереккөзден келуі мүмкін. Қолданба функциялары өзгеруі мүмкін."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Бұл қолданба <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> арқылы жаңартылсын ба?\n\nБұл қолданба әдетте <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> көмегімен жаңартылады. Басқа дереккөзден жаңартсаңыз, алдағы жаңартулар телефоныңыздағы кез келген дереккөзден келуі мүмкін. Қолданба функциялары өзгеруі мүмкін."</string>
<string name="install_failed" msgid="5777824004474125469">"Қолданба орнатылмады."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Пакетті орнатуға тыйым салынды."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Жаңа пакет пен бұрыннан бар пакеттің арасында қайшылық туындағандықтан, қолданба орнатылмады."</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 04dc574..4a221ac 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"បានដំឡើងកម្មវិធី។"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"តើអ្នកចង់ដំឡើងកម្មវិធីនេះដែរទេ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"តើអ្នកចង់ដំឡើងកំណែកម្មវិធីនេះដែរទេ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ដំឡើងកំណែកម្មវិធីនេះពី <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ឬ?\n\nកម្មវិធីនេះជាធម្មតាទទួលបានកំណែថ្មីពី <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចនឹងទទួលបានកំណែថ្មីនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរសព្ទរបស់អ្នក។ មុខងារកម្មវិធីអាចមានការផ្លាស់ប្ដូរ។"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ដំឡើងកំណែកម្មវិធីនេះពី <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ឬ?\n\nកម្មវិធីនេះជាធម្មតាទទួលបានកំណែថ្មីពី <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>។ តាមរយៈការដំឡើងកំណែពីប្រភពផ្សេង អ្នកអាចនឹងទទួលបានកំណែថ្មីនាពេលអនាគតពីប្រភពណាក៏បាននៅលើទូរសព្ទរបស់អ្នក។ មុខងារកម្មវិធីអាចមានការផ្លាស់ប្ដូរ។"</string>
<string name="install_failed" msgid="5777824004474125469">"មិនបានដំឡើងកម្មវិធីទេ។"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"កញ្ចប់ត្រូវបានទប់ស្កាត់មិនឱ្យដំឡើង។"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"កម្មវិធីមិនបានដំឡើងទេ ដោយសារកញ្ចប់កម្មវិធីមិនត្រូវគ្នាជាមួយកញ្ចប់ដែលមានស្រាប់។"</string>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 0378712..861e73e 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕೇ?\n\nಈ ಆ್ಯಪ್ ಸಾಮಾನ್ಯವಾಗಿ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ನಿಂದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಸ್ವೀಕರಿಸುತ್ತದೆ. ಬೇರೆ ಮೂಲವೊಂದರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿರುವ ಯಾವುದೇ ಮೂಲದಿಂದ ಭವಿಷ್ಯದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ನೀವು ಸ್ವೀಕರಿಸಬಹುದು. ಆ್ಯಪ್ನ ಕಾರ್ಯಚಟುವಟಿಕೆಯು ಬದಲಾಗಬಹುದು."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕೇ?\n\nಈ ಆ್ಯಪ್ ಸಾಮಾನ್ಯವಾಗಿ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ನಿಂದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ಸ್ವೀಕರಿಸುತ್ತದೆ. ಬೇರೆ ಮೂಲವೊಂದರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿರುವ ಯಾವುದೇ ಮೂಲದಿಂದ ಭವಿಷ್ಯದ ಅಪ್ಡೇಟ್ಗಳನ್ನು ನೀವು ಸ್ವೀಕರಿಸಬಹುದು. ಆ್ಯಪ್ನ ಕಾರ್ಯಚಟುವಟಿಕೆಯು ಬದಲಾಗಬಹುದು."</string>
<string name="install_failed" msgid="5777824004474125469">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿಲ್ಲ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಪ್ಯಾಕೇಜ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ಪ್ಯಾಕೇಜ್ನಂತೆ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿರುವ ಆ್ಯಪ್ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೇಜ್ ಜೊತೆಗೆ ಸಂಘರ್ಷವಾಗುತ್ತದೆ."</string>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index 14f9513..c51e507 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"앱이 설치되었습니다."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"이 앱을 설치하시겠습니까?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"이 앱을 업데이트하시겠습니까?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서 이 앱에 대한 업데이트를 받으시겠습니까?\n\n평소에는 <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>에서 앱을 업데이트했습니다. 다른 출처에서 앱을 업데이트하면 향후 휴대전화에 있는 어떤 출처에서든지 업데이트를 받을 수 있습니다. 앱 기능도 변경될 수 있습니다."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서 이 앱에 대한 업데이트를 받으시겠습니까?\n\n평소에는 <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>에서 앱을 업데이트했습니다. 다른 출처에서 앱을 업데이트하면 향후 휴대전화에 있는 어떤 출처에서든지 업데이트를 받을 수 있습니다. 앱 기능도 변경될 수 있습니다."</string>
<string name="install_failed" msgid="5777824004474125469">"앱이 설치되지 않았습니다."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"패키지 설치가 차단되었습니다."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"패키지가 기존 패키지와 충돌하여 앱이 설치되지 않았습니다."</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index 8b166c8..5821c82 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Колдонмо орнотулду."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Бул колдонмону орнотоюн деп жатасызбы?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Бул колдонмону жаңыртайын деп жатасызбы?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Колдонмону <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> аркылуу жаңыртасызбы?\n\nАдатта бул колдонмонун жаңыртууларын <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> жөнөтөт. Эгер колдонмону башка булактан жаңыртсаңыз, эртеңки күнү телефонуңуз ар кайсы булактан жаңырып, колдонмонун функциялары өзгөрүшү мүмкүн."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Колдонмону <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> аркылуу жаңыртасызбы?\n\nАдатта бул колдонмонун жаңыртууларын <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> жөнөтөт. Эгер колдонмону башка булактан жаңыртсаңыз, эртеңки күнү телефонуңуз ар кайсы булактан жаңырып, колдонмонун функциялары өзгөрүшү мүмкүн."</string>
<string name="install_failed" msgid="5777824004474125469">"Колдонмо орнотулган жок."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Топтомду орнотууга болбойт."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Башка топтом менен дал келбегендиктен колдонмо орнотулган жок."</string>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index f3912cc..9e609f2 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ຕິດຕັ້ງແອັບແລ້ວ."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ທ່ານຕ້ອງການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ທ່ານຕ້ອງການອັບເດດແອັບນີ້ບໍ່?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ອັບເດດແອັບນີ້ຈາກ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ບໍ?\n\nໂດຍທົ່ວໄປແລ້ວແອັບນີ້ຈະໄດ້ຮັບການອັບເດດຈາກ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. ການອັບເດດຈາກແຫຼ່ງທີ່ມາອື່ນອາດເຮັດໃຫ້ໂທລະສັບຂອງທ່ານໄດ້ຮັບການອັບເດດຈາກແຫຼ່ງທີ່ມານັ້ນໃນອະນາຄົດ. ຟັງຊັນການເຮັດວຽກຂອງແອັບອາດມີການປ່ຽນແປງ."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ອັບເດດແອັບນີ້ຈາກ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ບໍ?\n\nໂດຍທົ່ວໄປແລ້ວແອັບນີ້ຈະໄດ້ຮັບການອັບເດດຈາກ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. ການອັບເດດຈາກແຫຼ່ງທີ່ມາອື່ນອາດເຮັດໃຫ້ໂທລະສັບຂອງທ່ານໄດ້ຮັບການອັບເດດຈາກແຫຼ່ງທີ່ມານັ້ນໃນອະນາຄົດ. ຟັງຊັນການເຮັດວຽກຂອງແອັບອາດມີການປ່ຽນແປງ."</string>
<string name="install_failed" msgid="5777824004474125469">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເທື່ອ."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ແພັກເກດຖືກບລັອກບໍ່ໃຫ້ໄດ້ຮັບການຕິດຕັ້ງ."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ບໍ່ໄດ້ຕິດຕັ້ງແອັບເນື່ອງຈາກແພັກເກດຂັດແຍ່ງກັບແພັກເກດທີ່ມີຢູ່ກ່ອນແລ້ວ."</string>
diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml
index a7ec560e..1ee6f05 100644
--- a/packages/PackageInstaller/res/values-lt/strings.xml
+++ b/packages/PackageInstaller/res/values-lt/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Programa įdiegta."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ar norite įdiegti šią programą?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ar norite atnaujinti šią programą?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atnaujinti šią programą iš <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nŠi programa įprastai gauna naujinius iš <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Atnaujinę iš kito šaltinio, būsimus naujinius galite gauti iš bet kurio šaltinio telefone. Gali būti pakeistos programos funkcijos."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atnaujinti šią programą iš <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nŠi programa įprastai gauna naujinius iš <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Atnaujinę iš kito šaltinio, būsimus naujinius galite gauti iš bet kurio šaltinio telefone. Gali būti pakeistos programos funkcijos."</string>
<string name="install_failed" msgid="5777824004474125469">"Programa neįdiegta."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketas užblokuotas ir negali būti įdiegtas."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Programa neįdiegta, nes paketas nesuderinamas su esamu paketu."</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index 17dd542..dfb4399 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Lietotne ir instalēta."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vai vēlaties instalēt šo lietotni?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vai vēlaties atjaunināt šo lietotni?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vai atjaunināt šo lietotni, izmantojot “<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>”?\n\nŠī lietotne parasti saņem atjauninājumus no “<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>”. Veicot atjaunināšanu no cita avota, iespējams, turpmāk tālrunī saņemsiet atjauninājumus no jebkāda avota. Lietotnes funkcionalitāte var mainīties."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vai atjaunināt šo lietotni, izmantojot “<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>”?\n\nŠī lietotne parasti saņem atjauninājumus no “<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>”. Veicot atjaunināšanu no cita avota, iespējams, turpmāk tālrunī saņemsiet atjauninājumus no jebkāda avota. Lietotnes funkcionalitāte var mainīties."</string>
<string name="install_failed" msgid="5777824004474125469">"Lietotne nav instalēta."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakotnes instalēšana tika bloķēta."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Lietotne netika instalēta, jo pastāv pakotnes konflikts ar esošu pakotni."</string>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index 5aaea17..6cd2db3 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Апликацијата е инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Дали сакате да ја инсталирате апликацијава?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Дали сакате да ја ажурирате апликацијава?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Да се ажурира апликацијава од <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nАпликацијава вообичаено добива ажурирања од<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Со ажурирање од различен извор, може да добивате идни ажурирања од кој било извор на вашиот телефон. Функционалноста на апликацијата може да се промени."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Да се ажурира апликацијава од <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nАпликацијава вообичаено добива ажурирања од<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Со ажурирање од различен извор, може да добивате идни ажурирања од кој било извор на вашиот телефон. Функционалноста на апликацијата може да се промени."</string>
<string name="install_failed" msgid="5777824004474125469">"Апликацијата не е инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирањето на пакетот е блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација што не е инсталирана како пакет е во конфликт со постоечки пакет."</string>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index 0535843..9e4e99b 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തു."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?\n\nഈ ആപ്പിന് സാധാരണയായി <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നത് വഴി, നിങ്ങളുടെ ഫോണിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിക്കാൻ ഇടയുണ്ട്. ആപ്പ് ഫംഗ്ഷണാലിറ്റിയിൽ വ്യത്യാസം വന്നേക്കാം."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഈ ആപ്പ് അപ്ഡേറ്റ് ചെയ്യണോ?\n\nഈ ആപ്പിന് സാധാരണയായി <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> എന്നതിൽ നിന്ന് അപ്ഡേറ്റുകൾ ലഭിക്കാറുണ്ട്. മറ്റൊരു ഉറവിടത്തിൽ നിന്ന് അപ്ഡേറ്റ് ചെയ്യുന്നത് വഴി, നിങ്ങളുടെ ഫോണിലെ ഏത് ഉറവിടത്തിൽ നിന്നും ഭാവിയിൽ അപ്ഡേറ്റുകൾ ലഭിക്കാൻ ഇടയുണ്ട്. ആപ്പ് ഫംഗ്ഷണാലിറ്റിയിൽ വ്യത്യാസം വന്നേക്കാം."</string>
<string name="install_failed" msgid="5777824004474125469">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"പാക്കേജ് ഇൻസ്റ്റാൾ ചെയ്യുന്നത് ബ്ലോക്ക് ചെയ്തു."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"പാക്കേജിന് നിലവിലുള്ള പാക്കേജുമായി പൊരുത്തക്കേടുള്ളതിനാൽ, ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്തില്ല."</string>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index 84a3909..b427c85 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Аппыг суулгасан."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Та энэ аппыг суулгахыг хүсэж байна уу?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Та энэ аппыг шинэчлэхийг хүсэж байна уу?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Аппыг <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-с шинэчлэх үү?\n\nЭнэ апп ихэвчлэн <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-с шинэчлэлт хүлээн авдаг. Өөр эх сурвалжаас шинэчилснээр та ирээдүйн шинэчлэлтийг утсан дээрх аливаа эх сурвалжаас хүлээн авч магадгүй. Аппын ажиллагаа өөрчлөгдөж магадгүй."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Аппыг <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>-с шинэчлэх үү?\n\nЭнэ апп ихэвчлэн <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>-с шинэчлэлт хүлээн авдаг. Өөр эх сурвалжаас шинэчилснээр та ирээдүйн шинэчлэлтийг утсан дээрх аливаа эх сурвалжаас хүлээн авч магадгүй. Аппын ажиллагаа өөрчлөгдөж магадгүй."</string>
<string name="install_failed" msgid="5777824004474125469">"Аппыг суулгаагүй."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Багц суулгахыг блоклосон байна."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Багц одоо байгаа багцтай тохирохгүй байгаа тул аппыг суулгаж чадсангүй."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 367dede..17aa8ee 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"अॅप इंस्टॉल झाले."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तुम्हाला हे ॲप इंस्टॉल करायचे आहे का?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तुम्हाला हे ॲप अपडेट करायचे आहे का?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> वरून हे अॅप अपडेट करायचे आहे का?\n\nया अॅपला सामान्यतः <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> कडून अपडेट मिळतात. वेगवेगळ्या स्रोताकडून अपडेट करून, तुम्हाला तुमच्या फोनवरील कोणत्याही स्रोताकडून भविष्यातील अपडेट मिळू शकतात. अॅपची कार्यक्षमता बदलू शकते."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> वरून हे अॅप अपडेट करायचे आहे का?\n\nया अॅपला सामान्यतः <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> कडून अपडेट मिळतात. वेगवेगळ्या स्रोताकडून अपडेट करून, तुम्हाला तुमच्या फोनवरील कोणत्याही स्रोताकडून भविष्यातील अपडेट मिळू शकतात. अॅपची कार्यक्षमता बदलू शकते."</string>
<string name="install_failed" msgid="5777824004474125469">"अॅप इंस्टॉल झाले नाही."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अॅप इंस्टॉल झाले नाही."</string>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 6ab6622..9f3e55f 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikasi dipasang."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Adakah anda ingin memasang aplikasi ini?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Adakah anda mahu mengemas kini apl ini?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Kemas kinikan apl ini daripada <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nApl ini biasanya menerima kemaskinian daripada <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada telefon anda. Fungsi apl mungkin berubah."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Kemas kinikan apl ini daripada <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nApl ini biasanya menerima kemaskinian daripada <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dengan membuat kemaskinian daripada sumber yang berbeza, anda mungkin menerima kemaskinian masa hadapan daripada sebarang sumber pada telefon anda. Fungsi apl mungkin berubah."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikasi tidak dipasang."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakej ini telah disekat daripada dipasang."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Apl tidak dipasang kerana pakej bercanggah dengan pakej yang sedia ada."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index cb05b06..054bf13 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"အက်ပ်ထည့်သွင်းပြီးပါပြီ။"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ဤအက်ပ်ကို ထည့်သွင်းလိုသလား။"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ဤအက်ပ်ကို အပ်ဒိတ်လုပ်လိုသလား။"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ဤအက်ပ်ကို <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> မှ အပ်ဒိတ်လုပ်မလား။\n\nဤအက်ပ်သည် ပုံမှန်အားဖြင့် <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် ဖုန်းပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မှမဆို လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းလဲနိုင်သည်။"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ဤအက်ပ်ကို <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> မှ အပ်ဒိတ်လုပ်မလား။\n\nဤအက်ပ်သည် ပုံမှန်အားဖြင့် <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> မှ အပ်ဒိတ်များ ရရှိသည်။ မတူညီသောရင်းမြစ်မှ အပ်ဒိတ်လုပ်ခြင်းဖြင့် ဖုန်းပေါ်တွင် နောင်လာမည့်အပ်ဒိတ်များကို မည်သည့်ရင်းမြစ်မှမဆို လက်ခံရယူနိုင်သည်။ အက်ပ်လုပ်ဆောင်ချက် ပြောင်းလဲနိုင်သည်။"</string>
<string name="install_failed" msgid="5777824004474125469">"အက်ပ်မထည့်သွင်းရသေးပါ"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ပက်ကေ့ဂျ်ထည့်သွင်းခြင်းကို ပိတ်ထားသည်။"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ပက်ကေ့ဂျ်အဖြစ် ထည့်သွင်းမထားသော အက်ပ်သည် လက်ရှိပက်ကေ့ဂျ်နှင့် တိုက်နေသည်။"</string>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index 7532d7b..05045ab 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Appen er installert."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du oppdatere denne appen?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vil du oppdatere denne appen fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne appen mottar vanligvis oppdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du oppdaterer fra en annen kilde, kan du få fremtidige oppdateringer fra en hvilken som helst kilde på telefonen. Appfunksjonaliteten kan endres."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vil du oppdatere denne appen fra <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDenne appen mottar vanligvis oppdateringer fra <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Hvis du oppdaterer fra en annen kilde, kan du få fremtidige oppdateringer fra en hvilken som helst kilde på telefonen. Appfunksjonaliteten kan endres."</string>
<string name="install_failed" msgid="5777824004474125469">"Appen ble ikke installert."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Pakken er blokkert fra å bli installert."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen ble ikke installert fordi pakken er i konflikt med en eksisterende pakke."</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 0d7068e..81e410d 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"एप इन्स्टल गरियो।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"तपाईं यो एप इन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"तपाईं यो एप अपडेट गर्न चाहनुहुन्छ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"यो एप <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> बाट अपडेट गर्ने हो?\n\nयो एपले सामान्यतया <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> बाट अपडेट प्राप्त गर्छ। तपाईंले कुनै फरक स्रोतबाट अपडेट गर्नुभयो भने तपाईं भविष्यमा आफ्नो फोनमा भएको जुनसुकै स्रोतबाट अपडेटहरू प्राप्त गर्न सक्नुहुन्छ। यसो गर्दा एपका मुख्य सुविधाहरूले काम गर्ने तरिका परिवर्तन हुन सक्छ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"यो एप <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> बाट अपडेट गर्ने हो?\n\nयो एपले सामान्यतया <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> बाट अपडेट प्राप्त गर्छ। तपाईंले कुनै फरक स्रोतबाट अपडेट गर्नुभयो भने तपाईं भविष्यमा आफ्नो फोनमा भएको जुनसुकै स्रोतबाट अपडेटहरू प्राप्त गर्न सक्नुहुन्छ। यसो गर्दा एपका मुख्य सुविधाहरूले काम गर्ने तरिका परिवर्तन हुन सक्छ।"</string>
<string name="install_failed" msgid="5777824004474125469">"एप स्थापना गरिएन।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index fab6d51..c8a3e70 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App geïnstalleerd."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Wil je deze app installeren?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Wil je deze app updaten?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Deze app updaten via <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDeze app krijgt gewoonlijk updates via <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Als je updatet via een andere bron, kun je toekomstige updates via elke bron op je telefoon krijgen. De app-functionaliteit kan veranderen."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Deze app updaten via <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDeze app krijgt gewoonlijk updates via <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Als je updatet via een andere bron, kun je toekomstige updates via elke bron op je telefoon krijgen. De app-functionaliteit kan veranderen."</string>
<string name="install_failed" msgid="5777824004474125469">"App niet geïnstalleerd."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"De installatie van het pakket is geblokkeerd."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"App die niet is geïnstalleerd als pakket conflicteert met een bestaand pakket."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index c191714..563e93b 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ଆପ ଇନଷ୍ଟଲ ହୋଇଗଲା।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ଆପଣ ଏହି ଆପକୁ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ଆପଣ ଏହି ଆପକୁ ଅପଡେଟ୍ କରିବା ପାଇଁ ଚାହୁଁଛନ୍ତି କି?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ରୁ ଏହି ଆପକୁ ଅପଡେଟ କରିବେ?\n\nଏହି ଆପ ସାଧାରଣତଃ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଅପଡେଟଗୁଡ଼ିକ ପାଏ। ଏକ ଭିନ୍ନ ସୋର୍ସରୁ ଅପଡେଟ କରି ଆପଣଙ୍କ ଫୋନରେ ଯେ କୌଣସି ସୋର୍ସରୁ ଭବିଷ୍ୟତର ଅପଡେଟଗୁଡ଼ିକ ଆପଣ ପାଇପାରନ୍ତି। ଆପ କାର୍ଯ୍ୟକ୍ଷମତା ପରିବର୍ତ୍ତନ ହୋଇପାରେ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>ରୁ ଏହି ଆପକୁ ଅପଡେଟ କରିବେ?\n\nଏହି ଆପ ସାଧାରଣତଃ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>ରୁ ଅପଡେଟଗୁଡ଼ିକ ପାଏ। ଏକ ଭିନ୍ନ ସୋର୍ସରୁ ଅପଡେଟ କରି ଆପଣଙ୍କ ଫୋନରେ ଯେ କୌଣସି ସୋର୍ସରୁ ଭବିଷ୍ୟତର ଅପଡେଟଗୁଡ଼ିକ ଆପଣ ପାଇପାରନ୍ତି। ଆପ କାର୍ଯ୍ୟକ୍ଷମତା ପରିବର୍ତ୍ତନ ହୋଇପାରେ।"</string>
<string name="install_failed" msgid="5777824004474125469">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ଏହି ପ୍ୟାକେଜ୍କୁ ଇନଷ୍ଟଲ୍ କରାଯିବାରୁ ଅବରୋଧ କରାଯାଇଥିଲା।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ପୂର୍ବରୁ ଥିବା ପ୍ୟାକେଜ୍ ସହ ଏହି ପ୍ୟାକେଜ୍ର ସମସ୍ୟା ଉପୁଯିବାରୁ ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇପାରିଲା ନାହିଁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 1ef4921..41b1fce 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ਐਪ ਸਥਾਪਤ ਕੀਤੀ ਗਈ।"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?\n\nਇਸ ਐਪ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਹੁੰਦੀਆਂ ਹਨ। ਕਿਸੇ ਵੱਖਰੇ ਸਰੋਤ ਤੋਂ ਅੱਪਡੇਟ ਕਰ ਕੇ, ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਕਿਸੇ ਵੀ ਸਰੋਤ ਤੋਂ ਭਵਿੱਖੀ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ। ਐਪ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਬਦਲ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?\n\nਇਸ ਐਪ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> ਤੋਂ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਹੁੰਦੀਆਂ ਹਨ। ਕਿਸੇ ਵੱਖਰੇ ਸਰੋਤ ਤੋਂ ਅੱਪਡੇਟ ਕਰ ਕੇ, ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਕਿਸੇ ਵੀ ਸਰੋਤ ਤੋਂ ਭਵਿੱਖੀ ਅੱਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ। ਐਪ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਬਦਲ ਸਕਦੀ ਹੈ।"</string>
<string name="install_failed" msgid="5777824004474125469">"ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ਪੈਕੇਜ ਨੂੰ ਸਥਾਪਤ ਹੋਣ ਤੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ਪੈਕੇਜ ਦੇ ਇੱਕ ਮੌਜੂਦਾ ਪੈਕੇਜ ਨਾਲ ਵਿਵਾਦ ਹੋਣ ਕਰਕੇ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ।"</string>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index e44a391..360181c 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacja została zainstalowana."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Zainstalować tę aplikację?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Zaktualizować tę aplikację?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Zastosować do aplikacji aktualizację pochodzącą z tego źródła (<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>)?\n\nAktualizacje dla tej aplikacji zwykle dostarcza <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Jeśli zastosujesz aplikację pochodzącą z innego źródła, możesz w przyszłości otrzymywać na telefonie aktualizacje z dowolnych źródeł. Funkcje aplikacji mogą się zmienić."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Zastosować do aplikacji aktualizację pochodzącą z tego źródła (<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>)?\n\nAktualizacje dla tej aplikacji zwykle dostarcza <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Jeśli zastosujesz aplikację pochodzącą z innego źródła, możesz w przyszłości otrzymywać na telefonie aktualizacje z dowolnych źródeł. Funkcje aplikacji mogą się zmienić."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacja nie została zainstalowana."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalacja pakietu została zablokowana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacja nie została zainstalowana, bo powoduje konflikt z istniejącym pakietem."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 923c3bd..3fca451 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index de85f66..8dd1b7b 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App instalada."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Instalar esta app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Pretende atualizar esta app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar esta app a partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNormalmente, esta app recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se atualizar a partir de uma fonte diferente, poderá receber futuras atualizações de qualquer fonte no seu telemóvel. A funcionalidade da app pode sofrer alterações."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar esta app a partir de <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNormalmente, esta app recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se atualizar a partir de uma fonte diferente, poderá receber futuras atualizações de qualquer fonte no seu telemóvel. A funcionalidade da app pode sofrer alterações."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicação não instalada."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Foi bloqueada a instalação do pacote."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"A app não foi instalada porque o pacote entra em conflito com um pacote existente."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 923c3bd..3fca451 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"App instalado."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Quer instalar esse app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Quer atualizar esse app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Atualizar este app com <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nEste app normalmente recebe atualizações de <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Se você usa uma fonte diferente, o smartphone vai aceitar outras fontes para fazer as próximas atualizações. A funcionalidade do app pode mudar."</string>
<string name="install_failed" msgid="5777824004474125469">"O app não foi instalado."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"A instalação do pacote foi bloqueada."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Como o pacote tem um conflito com um pacote já existente, o app não foi instalado."</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index de4dd55..a53b664 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplicație instalată."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vrei să instalezi această aplicație?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vrei să actualizezi această aplicație?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Actualizezi aplicația de la <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDe obicei, aplicația primește actualizări de la <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe telefon. Funcționalitatea aplicației se poate modifica."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Actualizezi aplicația de la <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nDe obicei, aplicația primește actualizări de la <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Dacă actualizezi din altă sursă, este posibil să primești actualizări viitoare din orice sursă pe telefon. Funcționalitatea aplicației se poate modifica."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplicația nu a fost instalată."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalarea pachetului a fost blocată."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplicația nu a fost instalată deoarece pachetul intră în conflict cu un pachet existent."</string>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index d1f56fd..bf5cd9f 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Приложение установлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установить приложение?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Обновить приложение?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Обновить приложение отсюда: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nСтандартный источник обновлений этого приложения – <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Если обновить приложение из другого источника, для последующих обновлений будут использоваться любые источники на телефоне. Функции приложения могут измениться."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Обновить приложение отсюда: <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nСтандартный источник обновлений этого приложения – <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Если обновить приложение из другого источника, для последующих обновлений будут использоваться любые источники на телефоне. Функции приложения могут измениться."</string>
<string name="install_failed" msgid="5777824004474125469">"Приложение не установлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Установка пакета заблокирована."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Приложение не установлено, так как оно конфликтует с другим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index c300b68..faad85a 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"යෙදුම ස්ථාපනය කර ඇත."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"මෙම යෙදුම ස්ථාපනය කිරීමට ඔබට අවශ්යද?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"ඔබට මෙම යෙදුම යාවත්කාලීන කිරීමට අවශ්යද?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> වෙතින් මෙම යෙදුම යාවත්කාලීන කරන්න ද?\n\nමෙම යෙදුමට සාමාන්යයෙන් <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> සිට යාවත්කාලීන ලැබේ. වෙනස් මූලාශ්රයකින් යාවත්කාලීන කිරීමෙන්, ඔබට ඔබේ දුරකථනයෙහි ඕනෑම මූලාශ්රයකින් අනාගත යාවත්කාලීන ලැබීමට ඉඩ ඇත. යෙදුම් ක්රියාකාරිත්වය වෙනස් වීමට ඉඩ ඇත."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> වෙතින් මෙම යෙදුම යාවත්කාලීන කරන්න ද?\n\nමෙම යෙදුමට සාමාන්යයෙන් <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> සිට යාවත්කාලීන ලැබේ. වෙනස් මූලාශ්රයකින් යාවත්කාලීන කිරීමෙන්, ඔබට ඔබේ දුරකථනයෙහි ඕනෑම මූලාශ්රයකින් අනාගත යාවත්කාලීන ලැබීමට ඉඩ ඇත. යෙදුම් ක්රියාකාරිත්වය වෙනස් වීමට ඉඩ ඇත."</string>
<string name="install_failed" msgid="5777824004474125469">"යෙදුම ස්ථාපනය කර නැත."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"මෙම පැකේජය ස්ථාපනය කිරීම අවහිර කරන ලදි."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"පැකේජය දැනට පවතින පැකේජයක් සමග ගැටෙන නිසා යෙදුම ස්ථාපනය නොකරන ලදී."</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 58a3a35..41ab45a 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikácia bola nainštalovaná."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Chcete túto aplikáciu nainštalovať?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Chcete túto aplikáciu aktualizovať?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Chcete aktualizovať túto aplikáciu zo zdroja <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTúto aplikáciu obvykle aktualizuje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ak vykonáte aktualizáciu z iného zdroja, aplikácia sa v budúcnosti môže aktualizovať z ľubovoľného zdroja v telefóne. Funkcie aplikácie sa môžu zmeniť."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Chcete aktualizovať túto aplikáciu zo zdroja <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTúto aplikáciu obvykle aktualizuje <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ak vykonáte aktualizáciu z iného zdroja, aplikácia sa v budúcnosti môže aktualizovať z ľubovoľného zdroja v telefóne. Funkcie aplikácie sa môžu zmeniť."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikácia nebola nainštalovaná."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Inštalácia balíka bola zablokovaná."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikácia sa nenainštalovala, pretože balík je v konflikte s existujúcim balíkom."</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index 00c3d15..e426464 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacija je nameščena."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ali želite namestiti to aplikacijo?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ali želite posodobiti to aplikacijo?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Želite to aplikacijo posodobiti iz vira <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTa aplikacija običajno prejema posodobitve iz vira <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v telefonu. Funkcija aplikacije se lahko spremeni."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Želite to aplikacijo posodobiti iz vira <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nTa aplikacija običajno prejema posodobitve iz vira <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Če jo posodobite iz drugega vira, boste prihodnje posodobitve morda prejemali iz katerega koli vira v telefonu. Funkcija aplikacije se lahko spremeni."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacija ni nameščena."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Namestitev paketa je bila blokirana."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacija ni bila nameščena, ker je paket v navzkrižju z obstoječim paketom."</string>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index 9904bc0..b73832e 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Aplikacioni u instalua."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Dëshiron ta instalosh këtë aplikacion?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Dëshiron ta përditësosh këtë aplikacion?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Të përditësohet ky aplikacion nga <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKy aplikacion zakonisht merr përditësime nga <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Duke përditësuar nga një burim tjetër, mund të marrësh përditësime të ardhshme nga çdo burim në telefonin tënd. Funksionaliteti i aplikacionit mund të ndryshojë."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Të përditësohet ky aplikacion nga <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKy aplikacion zakonisht merr përditësime nga <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Duke përditësuar nga një burim tjetër, mund të marrësh përditësime të ardhshme nga çdo burim në telefonin tënd. Funksionaliteti i aplikacionit mund të ndryshojë."</string>
<string name="install_failed" msgid="5777824004474125469">"Aplikacioni nuk u instalua."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Instalimi paketës u bllokua."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Aplikacioni nuk u instalua pasi paketa është në konflikt me një paketë ekzistuese."</string>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index 5a0f52d..474e3ee 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Апликација је инсталирана."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Желите да инсталирате ову апликацију?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Желите да ажурирате ову апликацију?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Желите да ажурирате ову апликацију из извора <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nОва апликација се обично ажурира из извора <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на телефону. Функције апликације могу да се промене."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Желите да ажурирате ову апликацију из извора <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nОва апликација се обично ажурира из извора <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ако ажурирате из другог извора, можете да примате будућа ажурирања из било ког извора на телефону. Функције апликације могу да се промене."</string>
<string name="install_failed" msgid="5777824004474125469">"Апликација није инсталирана."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Инсталирање пакета је блокирано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Апликација није инсталирана јер је пакет неусаглашен са постојећим пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index ec6af2e..3fa54e8 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Appen har installerats."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Vill du installera den här appen?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Vill du uppdatera den här appen?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Vill du uppdatera den här appen från <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAppen tar vanligtvis emot uppdateringar från <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Genom att uppdatera från en annan källa kan du komma att ta emot framtida uppdateringar från olika källor på telefonen. Appfunktioner kan förändras."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Vill du uppdatera den här appen från <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nAppen tar vanligtvis emot uppdateringar från <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Genom att uppdatera från en annan källa kan du komma att ta emot framtida uppdateringar från olika källor på telefonen. Appfunktioner kan förändras."</string>
<string name="install_failed" msgid="5777824004474125469">"Appen har inte installerats."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketet har blockerats för installation."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Appen har inte installerats på grund av en konflikt mellan detta paket och ett befintligt paket."</string>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index 0eb224a..59d927e 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Imesakinisha programu."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ungependa kusakinisha programu hii?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ungependa kusasisha programu hii?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Ungependa kusasisha programu hii kutoka kwenye <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nProgramu hii kwa kawaida hupokea masasisho kutoka <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kwa kusasisha kutoka chanzo tofauti, huenda ukapokea masasisho ya siku zijazo kutoka chanzo chochote kwenye simu yako. Utendaji wa programu unaweza kubadilika."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Ungependa kusasisha programu hii kutoka kwenye <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nProgramu hii kwa kawaida hupokea masasisho kutoka <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Kwa kusasisha kutoka chanzo tofauti, huenda ukapokea masasisho ya siku zijazo kutoka chanzo chochote kwenye simu yako. Utendaji wa programu unaweza kubadilika."</string>
<string name="install_failed" msgid="5777824004474125469">"Imeshindwa kusakinisha programu."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Kifurushi kimezuiwa kisisakinishwe."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Programu haikusakinishwa kwa sababu kifurushi kinakinzana na kifurushi kingine kilichopo."</string>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index c60910c..52cc628 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ஆப்ஸ் நிறுவப்பட்டது."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"இந்த ஆப்ஸை நிறுவ வேண்டுமா?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> இலிருந்து இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?\n\nபொதுவாக இந்த ஆப்ஸ்<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> இலிருந்து புதுப்பிப்புகளைப் பெறும். வேறொன்றின் மூலம் புதுப்பித்தால் எதிர்காலத்தில் மொபைலில் வேறு இடத்திலிருந்து புதுப்பிப்புகளை நீங்கள் பெறக்கூடும். ஆப்ஸ் செயல்பாடுகள் மாறுபடக்கூடும்."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> இலிருந்து இந்த ஆப்ஸைப் புதுப்பிக்க வேண்டுமா?\n\nபொதுவாக இந்த ஆப்ஸ்<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> இலிருந்து புதுப்பிப்புகளைப் பெறும். வேறொன்றின் மூலம் புதுப்பித்தால் எதிர்காலத்தில் மொபைலில் வேறு இடத்திலிருந்து புதுப்பிப்புகளை நீங்கள் பெறக்கூடும். ஆப்ஸ் செயல்பாடுகள் மாறுபடக்கூடும்."</string>
<string name="install_failed" msgid="5777824004474125469">"ஆப்ஸ் நிறுவப்படவில்லை."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"இந்தத் தொகுப்பு நிறுவப்படுவதிலிருந்து தடுக்கப்பட்டது."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"இந்தத் தொகுப்பு ஏற்கனவே உள்ள தொகுப்புடன் முரண்படுவதால் ஆப்ஸ் நிறுவப்படவில்லை."</string>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 25673f3..6f2a0d6 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"యాప్ ఇన్స్టాల్ చేయబడింది."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"మీరు ఈ యాప్ను ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"మీరు ఈ యాప్ను అప్డేట్ చేయాలనుకుంటున్నారా?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ద్వారా ఈ యాప్ను అప్డేట్ చేయాలా?\n\nఈ యాప్ సాధారణంగా <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> నుండి అప్డేట్లను అందుకుంటుంది. వేరే సోర్స్ ద్వారా అప్డేట్ చేయడం వల్ల, భవిష్యత్తులో మీ ఫోన్లోని ఏ సోర్స్ ద్వారా అయినా అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ద్వారా ఈ యాప్ను అప్డేట్ చేయాలా?\n\nఈ యాప్ సాధారణంగా <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> నుండి అప్డేట్లను అందుకుంటుంది. వేరే సోర్స్ ద్వారా అప్డేట్ చేయడం వల్ల, భవిష్యత్తులో మీ ఫోన్లోని ఏ సోర్స్ ద్వారా అయినా అప్డేట్లను పొందవచ్చు. యాప్ ఫంక్షనాలిటీ మారవచ్చు."</string>
<string name="install_failed" msgid="5777824004474125469">"యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"ప్యాకేజీ ఇన్స్టాల్ కాకుండా బ్లాక్ చేయబడింది."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ప్యాకేజీ, అలాగే ఇప్పటికే ఉన్న ప్యాకేజీ మధ్య వైరుధ్యం ఉన్నందున యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index c8f3275..8a01bb4 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ติดตั้งแอปแล้ว"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"คุณต้องการติดตั้งแอปนี้ไหม"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"คุณต้องการอัปเดตแอปนี้ไหม"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"อัปเดตแอปนี้จาก <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ไหม\n\nโดยปกติแล้ว แอปนี้จะได้รับการอัปเดตจาก <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> การอัปเดตจากแหล่งที่มาอื่นอาจทำให้โทรศัพท์ของคุณได้รับการอัปเดตจากแหล่งที่มาใดก็ได้ในอนาคต ฟังก์ชันการทำงานของแอปอาจมีการเปลี่ยนแปลง"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"อัปเดตแอปนี้จาก <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> ไหม\n\nโดยปกติแล้ว แอปนี้จะได้รับการอัปเดตจาก <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> การอัปเดตจากแหล่งที่มาอื่นอาจทำให้โทรศัพท์ของคุณได้รับการอัปเดตจากแหล่งที่มาใดก็ได้ในอนาคต ฟังก์ชันการทำงานของแอปอาจมีการเปลี่ยนแปลง"</string>
<string name="install_failed" msgid="5777824004474125469">"ไม่ได้ติดตั้งแอป"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"มีการบล็อกแพ็กเกจไม่ให้ติดตั้ง"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ไม่ได้ติดตั้งแอปเพราะแพ็กเกจขัดแย้งกับแพ็กเกจที่มีอยู่"</string>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 4d516b5..37dbed9 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Na-install na ang app."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Gusto mo bang i-install ang app na ito?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Gusto mo bang i-update ang app na ito?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"I-update itong app na mula sa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKaraniwang nakakatanggap ang app na ito ng mga update mula sa <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Sa pag-update mula sa ibang pinagmulan, puwede kang makatanggap ng mga update mula sa anumang pinagmulan sa iyong telepono sa hinaharap. Posibleng magbago ang functionality ng app."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"I-update itong app na mula sa <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nKaraniwang nakakatanggap ang app na ito ng mga update mula sa <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Sa pag-update mula sa ibang pinagmulan, puwede kang makatanggap ng mga update mula sa anumang pinagmulan sa iyong telepono sa hinaharap. Posibleng magbago ang functionality ng app."</string>
<string name="install_failed" msgid="5777824004474125469">"Hindi na-install ang app."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Na-block ang pag-install sa package."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Hindi na-install ang app dahil nagkakaproblema ang package sa isang dati nang package."</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 050d398..8c384c1 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Uygulama yüklendi."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu uygulamayı yüklemek istiyor musunuz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu uygulamayı güncellemek istiyor musunuz?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu uygulama <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> kaynağından güncellensin mi?\n\nBu uygulama genellikle <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> kaynağından güncelleme alır. Farklı bir kaynaktan güncellerseniz ileride telefonunuzda herhangi bir kaynaktan güncelleme alabilirsiniz. Uygulama işlevselliği değişebilir."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu uygulama <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> kaynağından güncellensin mi?\n\nBu uygulama genellikle <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> kaynağından güncelleme alır. Farklı bir kaynaktan güncellerseniz ileride telefonunuzda herhangi bir kaynaktan güncelleme alabilirsiniz. Uygulama işlevselliği değişebilir."</string>
<string name="install_failed" msgid="5777824004474125469">"Uygulama yüklenmedi."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paketin yüklemesi engellendi."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Paket, mevcut bir paketle çakıştığından uygulama yüklenemedi."</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index ec10962..f4b594e 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Програму встановлено."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Установити цей додаток?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Оновити цей додаток?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Оновити цей додаток через <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗазвичай цей додаток отримує оновлення в інший спосіб (<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>). Якщо встановити оновлення з іншого джерела, надалі на ваш телефон зможуть надходити оновлення з будь-яких джерел. Це може змінити функції додатка."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Оновити цей додаток через <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nЗазвичай цей додаток отримує оновлення в інший спосіб (<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>). Якщо встановити оновлення з іншого джерела, надалі на ваш телефон зможуть надходити оновлення з будь-яких джерел. Це може змінити функції додатка."</string>
<string name="install_failed" msgid="5777824004474125469">"Програму не встановлено."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Встановлення пакета заблоковано."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Додаток не встановлено, оскільки пакет конфліктує з наявним пакетом."</string>
diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml
index b3b4c0d..fc4b26b 100644
--- a/packages/PackageInstaller/res/values-ur/strings.xml
+++ b/packages/PackageInstaller/res/values-ur/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"ایپ انسٹال ہو گئی۔"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"کیا آپ یہ ایپ انسٹال کرنا چاہتے ہیں؟"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"کیا آپ یہ ایپ اپ ڈیٹ کرنا چاہتے ہیں؟"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"اس ایپ کو <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> سے اپ ڈیٹ کریں؟\n\n اس ایپ کو عام طور پر <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> سے اپ ڈیٹس موصول ہوتی ہیں۔ کسی مختلف ذریعے سے اپ ڈیٹ کر کے، آپ اپنے فون پر کسی بھی ذریعے سے مستقبل کی اپ ڈیٹس حاصل کر سکتے ہیں۔ ایپ کی فعالیت تبدیل ہو سکتی ہے۔"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"اس ایپ کو <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> سے اپ ڈیٹ کریں؟\n\n اس ایپ کو عام طور پر <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> سے اپ ڈیٹس موصول ہوتی ہیں۔ کسی مختلف ذریعے سے اپ ڈیٹ کر کے، آپ اپنے فون پر کسی بھی ذریعے سے مستقبل کی اپ ڈیٹس حاصل کر سکتے ہیں۔ ایپ کی فعالیت تبدیل ہو سکتی ہے۔"</string>
<string name="install_failed" msgid="5777824004474125469">"ایپ انسٹال نہیں ہوئی۔"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"پیکج کو انسٹال ہونے سے مسدود کر دیا گیا تھا۔"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"ایپ انسٹال نہیں ہوئی کیونکہ پیکج ایک موجودہ پیکیج سے متصادم ہے۔"</string>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index 2993663c..f32ae7d 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Ilova o‘rnatildi."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bu ilovani oʻrnatmoqchimisiz?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bu ilova yangilansinmi?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Bu ilova <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> orqali yangilansinmi?\n\nBu ilova odatda <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> orqali yangilanishlar oladi. Boshqa manbadan yangilash orqali siz kelajakdagi yangilanishlarni telefoningizda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Bu ilova <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g> orqali yangilansinmi?\n\nBu ilova odatda <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g> orqali yangilanishlar oladi. Boshqa manbadan yangilash orqali siz kelajakdagi yangilanishlarni telefoningizda istalgan manbadan olishingiz mumkin. Ilova funksiyalari oʻzgarishi mumkin."</string>
<string name="install_failed" msgid="5777824004474125469">"Ilova o‘rnatilmadi."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Paket o‘rnatilishga qarshi bloklangan."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Paket mavjud paket bilan zid kelganligi uchun ilovani o‘rnatib bo‘lmadi."</string>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index f6ffa3a..051bc54 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Ứng dụng đã được cài đặt."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Bạn có muốn cài đặt ứng dụng này không?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Bạn có muốn cập nhật ứng dụng này không?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Cập nhật ứng dụng này của <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nỨng dụng này thường nhận thông tin cập nhật từ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Khi cập nhật từ một nguồn khác, trong tương lai, bạn có thể nhận thông tin cập nhật từ nguồn bất kỳ trên điện thoại của bạn. Chức năng ứng dụng có thể thay đổi."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Cập nhật ứng dụng này của <xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nỨng dụng này thường nhận thông tin cập nhật từ <xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Khi cập nhật từ một nguồn khác, trong tương lai, bạn có thể nhận thông tin cập nhật từ nguồn bất kỳ trên điện thoại của bạn. Chức năng ứng dụng có thể thay đổi."</string>
<string name="install_failed" msgid="5777824004474125469">"Ứng dụng chưa được cài đặt."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Đã chặn cài đặt gói."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Chưa cài đặt được ứng dụng do gói xung đột với một gói hiện có."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index 5c2d11f..c33c7ca 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"已安装应用。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安装此应用吗?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此应用吗?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要通过<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>更新此应用吗?\n\n此应用通常通过<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>接收更新。如果通过其他来源更新,手机未来可能会收到任何来源的更新。应用功能可能会变化。"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要通过<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>更新此应用吗?\n\n此应用通常通过<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>接收更新。如果通过其他来源更新,手机未来可能会收到任何来源的更新。应用功能可能会变化。"</string>
<string name="install_failed" msgid="5777824004474125469">"未安装应用。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系统已禁止安装该软件包。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"应用未安装:软件包与现有软件包存在冲突。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index b36770d..0bfbd6e 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝此應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新此應用程式嗎?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要從「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新此應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新此應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要從「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新此應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新此應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"套件已遭封鎖,無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"套件與現有的套件發生衝突,無法安裝應用程式。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index 2a87eb8..4f0f669 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"已安裝應用程式。"</string>
<string name="install_confirm_question" msgid="7663733664476363311">"要安裝這個應用程式嗎?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"要更新這個應用程式嗎?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新這個應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新這個應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"要透過「<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>」更新這個應用程式嗎?\n\n在正常情況下,系統會透過「<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>」更新這個應用程式。如果透過其他來源更新,手機未來可能會收到任何來源的更新。應用程式功能可能會有變動。"</string>
<string name="install_failed" msgid="5777824004474125469">"未安裝應用程式。"</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"系統已封鎖這個套件,因此無法安裝。"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"應用程式套件與現有套件衝突,因此未能完成安裝。"</string>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index ca9c63b..bcc4b71 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -26,7 +26,11 @@
<string name="install_done" msgid="5987363587661783896">"Uhlelo lokusebenza olufakiwe."</string>
<string name="install_confirm_question" msgid="7663733664476363311">"Ingabe ufuna ukufaka le app?"</string>
<string name="install_confirm_question_update" msgid="3348888852318388584">"Ingabe ufuna ukubuyekeza le app?"</string>
- <string name="install_confirm_question_update_owner_reminder" msgid="3750986542284587290">"Buyekeza le app kusuka ku-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNgokuvamile le app ithola izibuyekezo kusuka ku-<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ngokubuyekeza kusuka kumthombo ohlukile, ungase uthole izibuyekezo zesikhathi esizayo kusuka kunoma yimuphi umthombo efonini yakho. Okwenziwa yi-app kungase kushintshe."</string>
+ <!-- no translation found for install_confirm_question_update_owner_reminder (738046584021528374) -->
+ <skip />
+ <!-- no translation found for install_confirm_question_update_owner_reminder (3056133099508550163) -->
+ <skip />
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="3750986542284587290">"Buyekeza le app kusuka ku-<xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>?\n\nNgokuvamile le app ithola izibuyekezo kusuka ku-<xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g>. Ngokubuyekeza kusuka kumthombo ohlukile, ungase uthole izibuyekezo zesikhathi esizayo kusuka kunoma yimuphi umthombo efonini yakho. Okwenziwa yi-app kungase kushintshe."</string>
<string name="install_failed" msgid="5777824004474125469">"Uhlelo lokusebenza alufakiwe."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Iphakheji livinjiwe kusukela ekufakweni."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Uhlelo lokusebenza alufakiwe njengoba ukuphakheja kushayisana nephakheji elikhona."</string>
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index c52fde6..4eaa39b 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -38,11 +38,11 @@
<!-- Message for updating an existing app [CHAR LIMIT=NONE] -->
<string name="install_confirm_question_update">Do you want to update this app?</string>
<!-- Message for updating an existing app with update owner reminder [CHAR LIMIT=NONE] -->
- <string name="install_confirm_question_update_owner_reminder" product="tablet">Update this app from <xliff:g id="new_update_owner">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="existing_update_owner">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet"><p>Update this app from <b><xliff:g id="new_update_owner">%1$s</xliff:g></b>\?</p><p>This app normally receives updates from <b><xliff:g id="existing_update_owner">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your tablet. App functionality may change.</p></string>
<!-- Message for updating an existing app with update owner reminder [CHAR LIMIT=NONE] -->
- <string name="install_confirm_question_update_owner_reminder" product="tv">Update this app from <xliff:g id="new_update_owner">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="existing_update_owner">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv"><p>Update this app from <b><xliff:g id="new_update_owner">%1$s</xliff:g></b>\?</p><p>This app normally receives updates from <b><xliff:g id="existing_update_owner">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your TV. App functionality may change.</p></string>
<!-- Message for updating an existing app with update owner reminder [CHAR LIMIT=NONE] -->
- <string name="install_confirm_question_update_owner_reminder" product="default">Update this app from <xliff:g id="new_update_owner">%1$s</xliff:g>?\n\nThis app normally receives updates from <xliff:g id="existing_update_owner">%2$s</xliff:g>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default"><p>Update this app from <b><xliff:g id="new_update_owner">%1$s</xliff:g></b>\?</p><p>This app normally receives updates from <b><xliff:g id="existing_update_owner">%2$s</xliff:g></b>. By updating from a different source, you may receive future updates from any source on your phone. App functionality may change.</p></string>
<!-- [CHAR LIMIT=100] -->
<string name="install_failed">App not installed.</string>
<!-- Reason displayed when installation fails because the package was blocked
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index e071c11..411f1fa 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -49,6 +49,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.text.Html;
+import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -144,9 +146,12 @@
final CharSequence requestedUpdateOwnerLabel = getApplicationLabel(mCallingPackage);
if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
&& mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP) {
- viewToEnable.setText(
+ String updateOwnerString =
getString(R.string.install_confirm_question_update_owner_reminder,
- requestedUpdateOwnerLabel, existingUpdateOwnerLabel));
+ requestedUpdateOwnerLabel, existingUpdateOwnerLabel);
+ Spanned styledUpdateOwnerString =
+ Html.fromHtml(updateOwnerString, Html.FROM_HTML_MODE_LEGACY);
+ viewToEnable.setText(styledUpdateOwnerString);
mOk.setText(R.string.update_anyway);
} else {
mOk.setText(R.string.update);
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
deleted file mode 100644
index e68ef85..0000000
--- a/packages/SettingsLib/Spa/build.gradle
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 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.
- */
-
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-buildscript {
- ext {
- BUILD_TOOLS_VERSION = "30.0.3"
- MIN_SDK = 21
- TARGET_SDK = 33
- jetpack_compose_version = '1.4.0-beta01'
- jetpack_compose_compiler_version = '1.4.4'
- }
-}
-plugins {
- id 'com.android.application' version '8.0.0' apply false
- id 'com.android.library' version '8.0.0' apply false
- id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
-}
-subprojects {
- tasks.withType(KotlinCompile).configureEach {
- kotlinOptions {
- jvmTarget = "17"
- freeCompilerArgs = ["-Xjvm-default=all"]
- }
- }
-}
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
new file mode 100644
index 0000000..64b67d7
--- /dev/null
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.
+ */
+
+import com.android.build.gradle.BaseExtension
+import com.android.build.gradle.api.AndroidBasePlugin
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.android.library) apply false
+ alias(libs.plugins.kotlin.android) apply false
+}
+
+allprojects {
+ extra["jetpackComposeVersion"] = "1.4.0-beta01"
+}
+
+subprojects {
+ plugins.withType<AndroidBasePlugin> {
+ configure<BaseExtension> {
+ compileSdkVersion(33)
+
+ defaultConfig {
+ minSdk = 21
+ targetSdk = 34
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ }
+ }
+
+ afterEvaluate {
+ plugins.withType<AndroidBasePlugin> {
+ configure<BaseExtension> {
+ if (buildFeatures.compose == true) {
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.4.4"
+ }
+ }
+ }
+ }
+ }
+
+ tasks.withType<KotlinCompile> {
+ kotlinOptions {
+ jvmTarget = "17"
+ freeCompilerArgs = listOf("-Xjvm-default=all")
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/gallery/build.gradle b/packages/SettingsLib/Spa/gallery/build.gradle
deleted file mode 100644
index 212aa7b..0000000
--- a/packages/SettingsLib/Spa/gallery/build.gradle
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 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.
- */
-
-plugins {
- id 'com.android.application'
- id 'kotlin-android'
-}
-
-android {
- namespace 'com.android.settingslib.spa.gallery'
- compileSdk TARGET_SDK
- buildToolsVersion = BUILD_TOOLS_VERSION
-
- defaultConfig {
- applicationId "com.android.settingslib.spa.gallery"
- minSdk MIN_SDK
- targetSdk TARGET_SDK
- versionCode 1
- versionName "1.0"
- }
-
- sourceSets {
- main {
- kotlin {
- srcDir "src"
- }
- res.srcDirs = ["res"]
- manifest.srcFile "AndroidManifest.xml"
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
- buildFeatures {
- compose true
- }
- composeOptions {
- kotlinCompilerExtensionVersion jetpack_compose_compiler_version
- }
-}
-
-dependencies {
- implementation project(":spa")
-}
diff --git a/packages/SettingsLib/Spa/gallery/build.gradle.kts b/packages/SettingsLib/Spa/gallery/build.gradle.kts
new file mode 100644
index 0000000..7f689c1
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/build.gradle.kts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 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.
+ */
+
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+}
+
+android {
+ namespace = "com.android.settingslib.spa.gallery"
+
+ defaultConfig {
+ applicationId = "com.android.settingslib.spa.gallery"
+ versionCode = 1
+ versionName = "1.0"
+ }
+
+ sourceSets {
+ sourceSets.getByName("main") {
+ java.setSrcDirs(listOf("src"))
+ res.setSrcDirs(listOf("res"))
+ manifest.srcFile("AndroidManifest.xml")
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+}
+
+dependencies {
+ implementation(project(":spa"))
+}
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
new file mode 100644
index 0000000..9a16df8
--- /dev/null
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+[versions]
+agp = "8.0.2"
+dexmaker-mockito = "2.28.3"
+kotlin = "1.8.10"
+truth = "1.1"
+
+[libraries]
+dexmaker-mockito = { module = "com.linkedin.dexmaker:dexmaker-mockito", version.ref = "dexmaker-mockito" }
+truth = { module = "com.google.truth:truth", version.ref = "truth" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+android-library = { id = "com.android.library", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index ed85e33..33f49e3 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -14,9 +14,8 @@
# limitations under the License.
#
-#Thu Jul 14 10:36:06 CST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/packages/SettingsLib/Spa/settings.gradle b/packages/SettingsLib/Spa/settings.gradle.kts
similarity index 77%
rename from packages/SettingsLib/Spa/settings.gradle
rename to packages/SettingsLib/Spa/settings.gradle.kts
index 1c5a1ce..9909781 100644
--- a/packages/SettingsLib/Spa/settings.gradle
+++ b/packages/SettingsLib/Spa/settings.gradle.kts
@@ -16,20 +16,27 @@
pluginManagement {
repositories {
- gradlePluginPortal()
google()
mavenCentral()
+ gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ rulesMode.set(RulesMode.FAIL_ON_PROJECT_RULES)
+
repositories {
google()
mavenCentral()
- maven { url "https://jitpack.io"}
+ maven {
+ url = uri("https://jitpack.io")
+ content {
+ includeGroup("com.github.PhilJay")
+ }
+ }
}
}
rootProject.name = "SpaLib"
-include ':spa'
-include ':gallery'
-include ':testutils'
+include(":spa")
+include(":gallery")
+include(":testutils")
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
deleted file mode 100644
index a591366..0000000
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 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.
- */
-
-plugins {
- id 'com.android.library'
- id 'kotlin-android'
-}
-
-android {
- namespace 'com.android.settingslib.spa'
- compileSdk TARGET_SDK
- buildToolsVersion = BUILD_TOOLS_VERSION
-
- defaultConfig {
- minSdk MIN_SDK
- targetSdk TARGET_SDK
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- sourceSets {
- main {
- kotlin {
- srcDir "src"
- }
- res.srcDirs = ["res"]
- manifest.srcFile "AndroidManifest.xml"
- }
- androidTest {
- kotlin {
- srcDir "../tests/src"
- }
- res.srcDirs = ["../tests/res"]
- manifest.srcFile "../tests/AndroidManifest.xml"
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
- buildFeatures {
- compose true
- }
- composeOptions {
- kotlinCompilerExtensionVersion jetpack_compose_compiler_version
- }
- buildTypes {
- debug {
- testCoverageEnabled = true
- }
- }
-}
-
-dependencies {
- api "androidx.appcompat:appcompat:1.7.0-alpha02"
- api "androidx.slice:slice-builders:1.1.0-alpha02"
- api "androidx.slice:slice-core:1.1.0-alpha02"
- api "androidx.slice:slice-view:1.1.0-alpha02"
- api "androidx.compose.material3:material3:1.1.0-alpha06"
- api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
- api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
- api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
- api "androidx.lifecycle:lifecycle-livedata-ktx"
- api "androidx.lifecycle:lifecycle-runtime-compose"
- api "androidx.navigation:navigation-compose:2.6.0-alpha08"
- api "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha"
- api "com.google.android.material:material:1.7.0-alpha03"
- debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version"
- implementation "com.airbnb.android:lottie-compose:5.2.0"
-
- androidTestImplementation project(":testutils")
- androidTestImplementation 'androidx.lifecycle:lifecycle-runtime-testing'
- androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.3"
-}
-
-task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest") {
- group = "Reporting"
- description = "Generate Jacoco coverage reports after running tests."
-
- sourceDirectories.from = files("src")
- classDirectories.from = fileTree(
- dir: "$buildDir/tmp/kotlin-classes/debug",
- excludes: [
- "com/android/settingslib/spa/debug/**",
-
- // Excludes files forked from AndroidX.
- "com/android/settingslib/spa/widget/scaffold/CustomizedAppBar*",
- "com/android/settingslib/spa/widget/scaffold/TopAppBarColors*",
-
- // Excludes files forked from Accompanist.
- "com/android/settingslib/spa/framework/compose/DrawablePainter*",
-
- // Excludes inline functions, which is not covered in Jacoco reports.
- "com/android/settingslib/spa/framework/util/Collections*",
- "com/android/settingslib/spa/framework/util/Flows*",
-
- // Excludes debug functions
- "com/android/settingslib/spa/framework/compose/TimeMeasurer*",
-
- // Excludes slice demo presenter & provider
- "com/android/settingslib/spa/slice/presenter/Demo*",
- "com/android/settingslib/spa/slice/provider/Demo*",
- ],
- )
- executionData.from = fileTree(dir: "$buildDir/outputs/code_coverage/debugAndroidTest/connected")
-}
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
new file mode 100644
index 0000000..fac63361
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -0,0 +1,110 @@
+/*
+ * Copyright 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.
+ */
+
+plugins {
+ id(libs.plugins.android.library.get().pluginId)
+ id(libs.plugins.kotlin.android.get().pluginId)
+ jacoco
+}
+
+val jetpackComposeVersion: String? by extra
+
+android {
+ namespace = "com.android.settingslib.spa"
+
+ defaultConfig {
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ sourceSets {
+ sourceSets.getByName("main") {
+ kotlin.setSrcDirs(listOf("src"))
+ res.setSrcDirs(listOf("res"))
+ manifest.srcFile("AndroidManifest.xml")
+ }
+ sourceSets.getByName("androidTest") {
+ kotlin.setSrcDirs(listOf("../tests/src"))
+ res.setSrcDirs(listOf("../tests/res"))
+ manifest.srcFile("../tests/AndroidManifest.xml")
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ buildTypes {
+ getByName("debug") {
+ enableAndroidTestCoverage = true
+ }
+ }
+}
+
+dependencies {
+ api("androidx.appcompat:appcompat:1.7.0-alpha02")
+ api("androidx.slice:slice-builders:1.1.0-alpha02")
+ api("androidx.slice:slice-core:1.1.0-alpha02")
+ api("androidx.slice:slice-view:1.1.0-alpha02")
+ api("androidx.compose.material3:material3:1.1.0-alpha06")
+ api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
+ api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
+ api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
+ api("androidx.lifecycle:lifecycle-livedata-ktx")
+ api("androidx.lifecycle:lifecycle-runtime-compose")
+ api("androidx.navigation:navigation-compose:2.6.0-alpha08")
+ api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha")
+ api("com.google.android.material:material:1.7.0-alpha03")
+ debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
+ implementation("com.airbnb.android:lottie-compose:5.2.0")
+
+ androidTestImplementation(project(":testutils"))
+ androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing")
+}
+
+tasks.register<JacocoReport>("coverageReport") {
+ group = "Reporting"
+ description = "Generate Jacoco coverage reports after running tests."
+ dependsOn("connectedDebugAndroidTest")
+ sourceDirectories.setFrom(files("src"))
+ classDirectories.setFrom(
+ fileTree(layout.buildDirectory.dir("tmp/kotlin-classes/debug")) {
+ setExcludes(
+ listOf(
+ "com/android/settingslib/spa/debug/**",
+
+ // Excludes files forked from AndroidX.
+ "com/android/settingslib/spa/widget/scaffold/CustomizedAppBar*",
+ "com/android/settingslib/spa/widget/scaffold/TopAppBarColors*",
+
+ // Excludes files forked from Accompanist.
+ "com/android/settingslib/spa/framework/compose/DrawablePainter*",
+
+ // Excludes inline functions, which is not covered in Jacoco reports.
+ "com/android/settingslib/spa/framework/util/Collections*",
+ "com/android/settingslib/spa/framework/util/Flows*",
+
+ // Excludes debug functions
+ "com/android/settingslib/spa/framework/compose/TimeMeasurer*",
+
+ // Excludes slice demo presenter & provider
+ "com/android/settingslib/spa/slice/presenter/Demo*",
+ "com/android/settingslib/spa/slice/provider/Demo*",
+ )
+ )
+ }
+ )
+ executionData.setFrom(
+ fileTree(layout.buildDirectory.dir("outputs/code_coverage/debugAndroidTest/connected"))
+ )
+}
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle b/packages/SettingsLib/Spa/testutils/build.gradle
deleted file mode 100644
index 23a9add..0000000
--- a/packages/SettingsLib/Spa/testutils/build.gradle
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 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.
- */
-
-plugins {
- id 'com.android.library'
- id 'kotlin-android'
-}
-
-android {
- namespace 'com.android.settingslib.spa.testutils'
- compileSdk TARGET_SDK
- buildToolsVersion = BUILD_TOOLS_VERSION
-
- defaultConfig {
- minSdk MIN_SDK
- targetSdk TARGET_SDK
- }
-
- sourceSets {
- main {
- kotlin {
- srcDir "src"
- }
- manifest.srcFile "AndroidManifest.xml"
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
- buildFeatures {
- compose true
- }
- composeOptions {
- kotlinCompilerExtensionVersion jetpack_compose_compiler_version
- }
-}
-
-dependencies {
- api project(":spa")
-
- api "androidx.arch.core:core-testing:2.2.0-alpha01"
- api "androidx.compose.ui:ui-test-junit4:$jetpack_compose_version"
- api "com.google.truth:truth:1.1.3"
- api "org.mockito:mockito-core:2.21.0"
- debugApi "androidx.compose.ui:ui-test-manifest:$jetpack_compose_version"
-}
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle.kts b/packages/SettingsLib/Spa/testutils/build.gradle.kts
new file mode 100644
index 0000000..c3df9bc
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts
@@ -0,0 +1,46 @@
+/*
+ * Copyright 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.
+ */
+
+plugins {
+ id(libs.plugins.android.library.get().pluginId)
+ id(libs.plugins.kotlin.android.get().pluginId)
+}
+
+val jetpackComposeVersion: String? by extra
+
+android {
+ namespace = "com.android.settingslib.spa.testutils"
+
+ sourceSets {
+ sourceSets.getByName("main") {
+ java.setSrcDirs(listOf("src"))
+ manifest.srcFile("AndroidManifest.xml")
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+}
+
+dependencies {
+ api(project(":spa"))
+
+ api("androidx.arch.core:core-testing:2.2.0-alpha01")
+ api("androidx.compose.ui:ui-test-junit4:$jetpackComposeVersion")
+ api(libs.truth)
+ api(libs.dexmaker.mockito)
+ debugApi("androidx.compose.ui:ui-test-manifest:$jetpackComposeVersion")
+}
diff --git a/packages/SettingsLib/res/layout/dialog_with_icon.xml b/packages/SettingsLib/res/layout/dialog_with_icon.xml
index 54f8096..55d12eb 100644
--- a/packages/SettingsLib/res/layout/dialog_with_icon.xml
+++ b/packages/SettingsLib/res/layout/dialog_with_icon.xml
@@ -41,7 +41,6 @@
android:id="@+id/dialog_with_icon_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="10dp"
android:gravity="center"
style="@style/TextAppearanceSmall"/>
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 4ffaf1b..2ded3c6 100644
--- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
+++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
@@ -14,62 +14,48 @@
limitations under the License.
-->
-<ScrollView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/user_info_editor"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/user_info_scroll"
- android:padding="16dp">
-
- <LinearLayout
- android:layout_width="match_parent"
+ android:baselineAligned="false"
+ android:orientation="vertical">
+ <FrameLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:baselineAligned="false"
- android:orientation="vertical">
- <TextView
- android:id="@+id/user_info_title"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/EditUserDialogTitle"
- android:text="@string/user_info_settings_title"
- android:textDirection="locale"/>
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center">
- <ImageView
- android:id="@+id/user_photo"
- android:layout_width="@dimen/user_photo_size_in_user_info_dialog"
- android:layout_height="@dimen/user_photo_size_in_user_info_dialog"
- android:contentDescription="@string/user_image_photo_selector"
- android:scaleType="fitCenter"/>
- <ImageView
- android:id="@+id/add_a_photo_icon"
- android:layout_width="@dimen/add_a_photo_icon_size_in_user_info_dialog"
- android:layout_height="@dimen/add_a_photo_icon_size_in_user_info_dialog"
- android:src="@drawable/add_a_photo_circled"
- android:layout_gravity="bottom|right"/>
- </FrameLayout>
+ android:layout_gravity="center">
+ <ImageView
+ android:id="@+id/user_photo"
+ android:layout_width="@dimen/user_photo_size_in_user_info_dialog"
+ android:layout_height="@dimen/user_photo_size_in_user_info_dialog"
+ android:contentDescription="@string/user_image_photo_selector"
+ android:scaleType="fitCenter"/>
+ <ImageView
+ android:id="@+id/add_a_photo_icon"
+ android:layout_width="@dimen/add_a_photo_icon_size_in_user_info_dialog"
+ android:layout_height="@dimen/add_a_photo_icon_size_in_user_info_dialog"
+ android:src="@drawable/add_a_photo_circled"
+ android:layout_gravity="bottom|right"/>
+ </FrameLayout>
- <EditText
- android:id="@+id/user_name"
- android:layout_width="match_parent"
- android:layout_height="@dimen/user_name_height_in_user_info_dialog"
- android:layout_gravity="center"
- android:minWidth="200dp"
- android:layout_marginStart="6dp"
- android:minHeight="@dimen/min_tap_target_size"
- android:ellipsize="end"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart"
- android:inputType="text|textCapWords"
- android:selectAllOnFocus="true"
- android:hint="@string/user_nickname"
- android:maxLength="100"/>
+ <EditText
+ android:id="@+id/user_name"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/user_name_height_in_user_info_dialog"
+ android:layout_gravity="center"
+ android:minWidth="200dp"
+ android:layout_marginStart="6dp"
+ android:minHeight="@dimen/min_tap_target_size"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAlignment="viewStart"
+ android:inputType="text|textCapWords"
+ android:selectAllOnFocus="true"
+ android:hint="@string/user_nickname"
+ android:maxLength="100"/>
- </LinearLayout>
+</LinearLayout>
-</ScrollView>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 119bb73..556768f 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -84,7 +84,7 @@
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Ontkoppel"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Ontkoppel tans…"</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"Verbind tans…"</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"Verbind tans …"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Gekoppel<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Verbind tans…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Gekoppel (geen foon nie)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-oudio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD oudio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Gehoortoestelle"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-oudio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Gekoppel aan gehoortoestelle"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Gekoppel aan LE-oudio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Gekoppel aan media-oudio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Gekoppel aan foonoudio"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruik vir foonoudio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruik vir lêeroordrag"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruik vir invoer"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruik vir gehoortoestelle"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gebruik vir LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Bind saam"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BIND SAAM"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skermlaag wys huidige raakdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Wys tikke"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Wys visuele terugvoer vir tikke"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Wys oppervlakopdaterings"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flits totale vensteroppervlakke wanneer dit opdateer"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Wys aansigopdaterings"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Hierdie foon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Hierdie tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan nie op hierdie toestel speel nie"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Gradeer rekening op om oor te skakel"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 89d68c3..cb6ca3d 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"የሲም መዳረሻ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"ኤችዲ ኦዲዮ፦ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"ኤችዲ ኦዲዮ"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"አጋዥ መስሚያዎች"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ኦዲዮ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ከአጋዥ መስሚያዎች ጋር ተገናኝቷል"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ከLE ኦዲዮ ጋር ተገናኝቷል"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ወደ ማህደረ መረጃ አውዲዮ ተያይዟል"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ወደ ስልክ አውዲዮ ተያይዟል"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ለስልክ ድምፅ ተጠቀም"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ለፋይል ዝውውር ተጠቀም"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ለውፅአት ተጠቀም"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ለአጋዥ መስሚያዎች ይጠቀሙ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"የማያ ተደራቢ የአሁኑን የCPU አጠቃቀም እያሳየ ነው።"</string>
<string name="show_touches" msgid="8437666942161289025">"ነካ ማድረጎችን አሳይ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ለነካ ማድረጎች ምስላዊ ግብረመልስን አሳይ"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"የእይታ ዝማኔዎችን አሳይ"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ይህ ስልክ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ይህ ጡባዊ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምጽ ማውጫ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"በዚህ መሣሪያ ላይ ማጫወት አልተቻለም"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ለመቀየር መለያ ያልቁ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index f7e2b2d..024f591 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"الوصول إلى شريحة SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"صوت عالي الدقة: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"صوت عالي الدقة"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"سماعات الأذن الطبية"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"تمّ التوصيل بسماعات الأذن الطبية"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"متصل بـ LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"متصل بالإعدادات الصوتية للوسائط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"متصل بالإعدادات الصوتية للهاتف"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"الاستخدام لإعدادات الهاتف الصوتية"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"استخدامه لنقل الملفات"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"استخدام للإدخال"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"استخدام سماعات الأذن الطبية"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"عرض بيانات اللمس الحالية فوق المحتوى على الشاشة"</string>
<string name="show_touches" msgid="8437666942161289025">"عرض النقرات"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"عرض التعليقات المرئية للنقرات"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"إظهار تحديثات العرض"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"هذا الهاتف"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"هذا الجهاز اللوحي"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"لا يمكن تشغيل الوسائط هنا"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"يجب ترقية الحساب للتبديل"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 594ed7b..40fffef 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ছিমৰ এক্সেছ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"এইচ্ছডি অডিঅ’"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"শ্ৰৱণ যন্ত্ৰ"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE অডিঅ’"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"শ্ৰৱণ যন্ত্ৰলৈ সংযোগ কৰা হৈছে"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিঅ’ৰ সৈতে সংযোগ কৰক"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ফ\'ন অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ফাইল স্থানান্তৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ইনপুটৰ বাবে ব্যৱহাৰ কৰক"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"শ্ৰৱণ যন্ত্ৰৰ বাবে ব্যৱহাৰ কৰক"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"চলিত স্পৰ্শ-বিষয়ক তথ্যসহ স্ক্ৰীন অভাৰলে’"</string>
<string name="show_touches" msgid="8437666942161289025">"টেপসমূহ দেখুৱাওক"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"ভিউৰ আপডে’ট দেখুৱাওক"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফ’নটো"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"এই টেবলেটটো"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"এই ডিভাইচটো প্লে\' কৰিব নোৱাৰি"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"সলনি কৰিবলৈ একাউণ্ট আপগ্ৰে’ড কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 0b4779f..80cdf60 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-karta giriş"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Eşitmə cihazları"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Eşitmə Aparatlarına qoşuldu"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audiosuna qoşulub"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Media audioya birləşdirilib"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon audiosuna qoşulu"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Telefon audiosu istifadə edin"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Fayl transferi üçün istifadə edin"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Daxiletmə üçün istifadə edin"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Eşitmə Aparatları üçün istifadə edin"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO üçün istifadə edin"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Qoşulsun"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"QOŞULSUN"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Toxunuş və jest datası göstərilsin"</string>
<string name="show_touches" msgid="8437666942161289025">"Vizual reaksiya"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Toxunuşa vizual reaksiya verilsin"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Səth yenilənməsi göstərilsin"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Pəncərə səthi təzələnəndə işıqlansın"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Baxış yenilənməsi göstərilsin"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu planşet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oxutmaq olmur"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Keçirmək üçün hesabı güncəllə"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 298835f..cb226b7 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM kartici"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezano sa slušnim aparatima"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa zvukom telefona"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Korišćenje za audio telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Korišćenje za prenos datoteka"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Koristi za ulaz"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Koristi za slušne aparate"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Koristite za LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Preklopni element sa trenutnim podacima o dodiru"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikazuj dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikazuje vizuelne povratne informacije za dodire"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Osvetljava sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ne možete da pustite na ovom uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite nalog radi prebacivanja"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 666dbb1..dc32113 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Слыхавыя апараты"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Падключана да слыхавых апаратаў"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Падключана да LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Падключана да аўдыё медыа"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Падключана да аўдыё тэлефона"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Выкарыстоўваць для аўдыё тэлефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Выкарыстоўваць для перадачы файлаў"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Выкарыстоўваць для ўводу"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Выкарыстоўваць для слыхавых апаратаў"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -304,7 +307,7 @@
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Паказваць на экране націсканні і жэсты"</string>
<string name="show_touches" msgid="8437666942161289025">"Паказваць дакрананні"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Паказваць візуалізацыю дакрананняў"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Паказаць абнаўленні"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 9446634..2928dd9 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Достъп до SIM картата"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Висококачествено аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Висококачествено аудио"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слухови апарати"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Установена е връзка със слухов апарат"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Свързано с LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Установена е връзка с медийно аудио"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Връзка със звука на телефона"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Използване на телефон за аудио"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Използване на за пренос на файлове"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Да се използва за въвеждане"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Използване за слухови апарати"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Насл. на екран показва текущи данни при докосване"</string>
<string name="show_touches" msgid="8437666942161289025">"Показване на докосванията"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Показване на визуална обр. връзка за докосванията"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Актуализации на изгледите"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Този телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Този таблет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Възпроизвеждането не е възможно на това устройство"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надстройте профила, за да превключите"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 0eb5b75..d8c991fe 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"সিম অ্যাক্সেস"</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="58154575573984914">"হিয়ারিং এড"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE অডিও"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"হিয়ারিং এডের সাথে কানেক্ট করা হয়েছে"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিও কানেক্ট করা হয়েছে"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিওতে কানেক্ট রয়েছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফোন অডিওতে কানেক্ট"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ইনপুটের জন্য ব্যবহার করুন"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"হিয়ারিং এডের জন্য ব্যবহার করুন"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"স্ক্রিন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string>
<string name="show_touches" msgid="8437666942161289025">"আলতো চাপ দেখান"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"আলতো চাপ দিলে ভিজ্যুয়াল প্রতিক্রিয়া দেখান"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"ভিউয়ের আপডেট দেখুন"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফোন"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"এই ট্যাবলেট"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফোনটি"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"এই ডিভাইসে চালানো যাবে না"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"পাল্টাতে অ্যাকাউন্ট আপগ্রেড করুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 345cad1..ad973fb 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM-u"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezan na slušne aparate"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s LE zvukom"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano na zvuk telefona"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Koristi za zvuk telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Koristi za prijenos fajlova"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Koristi kao ulaz"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Korištenje za slušne aparate"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Koristi za: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Preklapanje ekrana s trenutnim podacima o dodiru"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikaz vizuelnih povratnih informacija za dodire"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja za površinu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Osvjetljava sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nije moguće reproducirati na uređaju"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite račun da promijenite"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 899bc7d..a1e7933 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accés a la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Àudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Àudio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audiòfons"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"S\'ha connectat als audiòfons"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connectat a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connectat a l\'àudio del mitjà"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connectat a àudio del telèfon"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilitza-ho per a l\'àudio del telèfon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilitza per a la transferència de fitxers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilitza per a entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utilitza per als audiòfons"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utilitza per a LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincula"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"VINCULA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposa les dades dels tocs a la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostra els tocs"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra la ubicació visual dels tocs"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Canvis de superfície"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Il·lumina superfícies de finestres en actualitzar-se"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Actualitzacions de visualitzacions"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Aquest telèfon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Aquesta tauleta"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No es pot reproduir en aquest dispositiu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualitza el compte per canviar"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 1c8fe92..11fb32d9 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Přístup k SIM kartě"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Naslouchátka"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Připojeno k naslouchátkům"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Připojeno k LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Připojeno ke zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Připojeno k náhlavní soupravě"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Umožňuje připojení náhlavní soupravy"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Použít pro přenos souborů"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Použít pro vstup"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Použít pro naslouchátka"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Používat pro LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Spárovat"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SPÁROVAT"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Překryvná vrstva zobrazuje aktuální data o dotycích"</string>
<string name="show_touches" msgid="8437666942161289025">"Zobrazovat klepnutí"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Zobrazovat vizuální zpětnou vazbu pro klepnutí"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Zobrazit obnovení obsahu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Rozbliká obsah okna při aktualizaci"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ukazovat aktualizace zobrazení"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok s reproduktorem"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"V zařízení nelze přehrávat"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Účet je třeba upgradovat"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 9253148..11e92de 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Adgang til SIM-kort"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Høreapparater"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-lyd"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Forbundet til høreapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Forbundet med LE-lyd"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Forbundet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Forbundet til telefonlyd"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Brug til telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Brug til filoverførsel"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Brug til input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Brug til høreapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Brug med LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Par"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ACCEPTÉR PARRING"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skærmoverlejringen viser de aktuelle berøringsdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Vis tryk"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vis visuel feedback ved tryk"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Vis overfladeopdateringer"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fremhæv hele vinduesoverflader, når de opdateres"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Se visningsopdateringer"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Denne tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan ikke afspilles på denne enhed"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Opgrader kontoen for at skifte"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 4c6f0c1..3c9b177 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Zugriff auf SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-Audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hörgeräte"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Mit Hörhilfen verbunden"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Mit LE Audio verbunden"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbunden mit Medien-Audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbunden mit Telefon-Audio"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Für Telefon-Audio verwenden"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Für Dateiübertragung verwenden"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Für Eingabe verwenden"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Für Hörhilfen verwenden"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Für LE_AUDIO verwenden"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppeln"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELN"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay mit aktuellen Daten zu Tippaktionen anzeigen"</string>
<string name="show_touches" msgid="8437666942161289025">"Fingertippen visualisieren"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Bei Fingertippen visuelles Feedback anzeigen"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Oberflächenaktualisierungen hervorheben"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Gesamte Fensteroberflächen blinken bei Aktualisierung"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Aktualisierungen von Ansichten hervorheben"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 64e9bcf..d03581a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Βοηθήματα ακοής"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Έγινε σύνδεση σε βοηθήματα ακοής"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Συνδέθηκε σε LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Συνδέθηκε σε ήχο πολυμέσων"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Συνδεδεμένο στον ήχο τηλεφώνου"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Χρήση για ήχο τηλεφώνου"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Χρήση για τη μεταφορά αρχείων"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Χρήση για είσοδο"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Χρήση για βοηθήματα ακοής"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Επικάλ.οθόνης για προβολή τρεχόντων δεδ/νων αφής"</string>
<string name="show_touches" msgid="8437666942161289025">"Εμφάνιση πατημάτων"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Εμφάνιση οπτικών σχολίων για πατήματα"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Εμφάνιση ενημερώσεων επιφάνειας"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Προβολή Flash ολόκλ. των επιφ παραθ. όταν ενημερ."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Εμφάνιση ενημερ. προβολής"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Αυτό το tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφ."</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Δεν είναι δυνατή η αναπαραγωγή σε αυτήν τη συσκευή"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Αναβαθμίστε τον λογαριασμό για εναλλαγή"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 6779e89..25d2dd2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM access"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hearing aids"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connected to hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Use for phone audio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Use for file transfer"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Use for input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Use for Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Use for hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Use for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pair"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAIR"</string>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 9ee30e1..aab6224 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM Access"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hearing aids"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connected to hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Use for phone audio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Use for file transfer"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Use for input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Use for Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Use for hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Use for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pair"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAIR"</string>
@@ -355,6 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
+ <string name="show_key_presses" msgid="6360141722735900214">"Show key presses"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Show visual feedback for physical key presses"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 6779e89..25d2dd2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM access"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hearing aids"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connected to hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Use for phone audio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Use for file transfer"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Use for input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Use for Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Use for hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Use for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pair"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAIR"</string>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 6779e89..25d2dd2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM access"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hearing aids"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connected to hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Use for phone audio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Use for file transfer"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Use for input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Use for Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Use for hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Use for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pair"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAIR"</string>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Can\'t play on this device"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade account to switch"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 9ad8a39..d69cda5 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM Access"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Hearing aids"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Connected to hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Use for phone audio"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Use for file transfer"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Use for input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Use for Hearing Aids"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Use for hearing aids"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Use for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pair"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAIR"</string>
@@ -355,6 +355,8 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Screen overlay showing current touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Show taps"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Show visual feedback for taps"</string>
+ <string name="show_key_presses" msgid="6360141722735900214">"Show key presses"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Show visual feedback for physical key presses"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Show surface updates"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash entire window surfaces when they update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Show view updates"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 8946365..f4b4153 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso a SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audífonos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"audio de bajo consumo"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audífonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a audio de bajo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del dispositivo"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilizar para el audio del dispositivo"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilizar para la transferencia de archivos"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizar para entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar para audífonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincular"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Muestra los datos táctiles en la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar presiones"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Muestra la ubicación de las presiones en la pantalla"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Ver actualiz. de superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Destello en superficie por actualización"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mostrar cambios de vista"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Conector de la bocina"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8268682..b6ed91e 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso a tarjeta SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audífonos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audífonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio del medio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del teléfono"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilizar para audio del teléfono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Uso de la transferencia de archivos"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar con audífonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar en LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Emparejar"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"EMPAREJAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superpone los datos de las pulsaciones en la pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Muestra la ubicación de los toques en la pantalla"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar cambios de superficies"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Hace parpadear todas las superficies de la ventana cuando se actualizan"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver actualizaciones de vista"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz base"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"No se puede reproducir en este dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Actualiza la cuenta para cambiar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 8e30e3d..023af0b 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Juurdepääs SIM-ile"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-heli: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-heli"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Kuuldeaparaadid"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Kuuldeaparaatidega ühendatud"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ühendatud üksusega LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ühendatud meediumiheliga"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ühendatud telefoniheliga"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Kasuta telefoniheli jaoks"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Kasutage failide edastamiseks"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Kasutage sisendi jaoks"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Kasuta kuulmisaparaatide puhul"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Üksuse LE_AUDIO kasutamine"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Seo"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SEO"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Praegusi puuteandmeid kuvav ekraani ülekate"</string>
<string name="show_touches" msgid="8437666942161289025">"Kuva puudutused"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Kuvab puudutuste visuaalse tagasiside"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Näita pinna värskendusi"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Akna pinna värskendamiseks kirjuta kogu akna pind üle"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Kuva ekraanikuva värskendusi"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"See telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"See tahvelarvuti"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Selles seadmes ei saa esitada"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lülitamiseks täiendage kontot"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7d64cfa..fcb6fd1 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -99,8 +99,8 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ezk. gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Esk- gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktibo"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktibo, ezkerreko audifonoa soilik"</string>
- <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktibo, eskuineko audifonoa soilik"</string>
+ <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>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Euskarriaren audioa"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefono-deiak"</string>
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIMerako sarbidea"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Kalitate handiko audioa: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Kalitate handiko audioa"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audifonoak"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Kontsumo txikiko Bluetooth bidezko audioa"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Audifonoetara konektatuta"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audio-ra konektatuta"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Euskarriaren audiora konektatuta"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefonoaren audiora konektatuta"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Erabili telefonoaren audiorako"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Erabili fitxategi-transferentziarako"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Erabili idazketarako"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Erabili audifonoak"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Erabili LE_AUDIO-rako"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parekatu"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREKATU"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ukipen-datuak erakusteko pantaila-gainjartzea"</string>
<string name="show_touches" msgid="8437666942161289025">"Erakutsi sakatutakoa"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Erakutsi sakatutako elementuak"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Erakutsi azaleko aldaketak"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Distirarazi leiho osoen azalak haiek eguneratzean"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Erakutsi ikuspegi-aldaketak"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefono hau"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tableta hau"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ezin da erreproduzitu gailu honetan"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Aldatzeko, bertsio-berritu kontua"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 3ba5436..8daf78a 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"دسترسی سیمکارت"</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="58154575573984914">"سمعک"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"صدای کممصرف"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"به سمعک متصل شد"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"به «صدای کممصرف» وصل است"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"به رسانه صوتی متصل شد"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"به تلفن صوتی متصل شد"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"استفاده برای تلفن صوتی"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"استفاده برای انتقال فایل"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"استفاده برای چاپ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"استفاده کردن برای سمعک"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -231,9 +234,9 @@
<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">"مرتبط کردن دستگاه با رمزینه پاسخسریع"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"جفت کردن دستگاه با رمزینه پاسخسریع"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"دستگاههای جدید را بااستفاده از اسکنر رمزینه پاسخسریع مرتبط کنید"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"مرتبط کردن دستگاه با کد مرتبطسازی"</string>
+ <string name="adb_pair_method_code_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>
@@ -242,13 +245,13 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"اثرانگشت دستگاه: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"اتصال ناموفق"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"مطمئن شوید که <xliff:g id="DEVICE_NAME">%1$s</xliff:g> به شبکه درستی متصل شده باشد"</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"مرتبط کردن با دستگاه"</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_failed_title" msgid="3426758947882091735">"مرتبطسازی ناموفق"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"مطمئن شوید که دستگاه به همان شبکه متصل باشد."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"دستگاه را ازطریق Wi‑Fi و با اسکن کردن رمزینه پاسخسریع مرتبط کنید"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"مرتبطسازی دستگاه…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"مرتبط کردن دستگاه انجام نشد. یا رمزینه پاسخسریع اشتباه بوده است، یا دستگاه به همان شبکه متصل نیست."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"جفت کردن دستگاه انجام نشد. یا رمزینه پاسخسریع اشتباه بوده است، یا دستگاه به همان شبکه متصل نیست."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"نشانی IP و درگاه"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"اسکن رمزینه پاسخسریع"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"دستگاه را ازطریق Wi‑Fi و با اسکن کردن رمزینه پاسخسریع مرتبط کنید"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"همپوشانی صفحهنمایش با نمایش داده لمسی فعلی"</string>
<string name="show_touches" msgid="8437666942161289025">"نمایش ضربهها"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"نمایش بازخورد تصویری برای ضربهها"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"نمایش بهروزرسانیهای نما"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"هماکنون"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"این تلفن"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"این رایانه لوحی"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"نمیتوان در این دستگاه پخش کرد"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"برای تغییر، حساب را ارتقا دهید"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index d1bf50a..b469cbc 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-kortin käyttö"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ääni: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ääni"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Kuulolaitteet"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Yhdistetty kuulolaitteisiin"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio yhdistetty"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Yhdistetty median ääneen"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Yhdistetty puhelimen ääneen"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Käytä puhelimen äänille"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Käytä tiedostojen siirtoon"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Käytä syöttöön"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Käytä kuulolaitteilla"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Käyttö: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Muodosta laitepari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"MUODOSTA LAITEPARI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Näytön peittokuva näyttää nykyiset kosketustiedot"</string>
<string name="show_touches" msgid="8437666942161289025">"Näytä kosketus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Anna visuaalista palautetta kosketuksesta"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Näytä pintapäivitykset"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Väläytä koko ikkunoiden pinnat päivitettäessä"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Näytä näyttöpäivitykset"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tämä puhelin"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tämä tabletti"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ei voi toistaa tällä laitteella"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Vaihda päivittämällä tili"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 11579af..06d8373 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accès à la carte SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Prothèses auditives"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connecté aux prothèses auditives"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté par LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté à l\'audio du téléphone"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utiliser pour les paramètres audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utiliser pour le transfert de fichiers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utiliser comme entrée"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utiliser avec les prothèses auditives"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utiliser pour LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Associer"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ASSOCIER"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposition écran indiquant données actuelles"</string>
<string name="show_touches" msgid="8437666942161289025">"Afficher éléments sélect."</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afficher repère visuel pour éléments sélectionnés"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Afficher mises à jour surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Faire clignoter les surfaces à chaque mise à jour"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Afficher m. à j. affichage"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de faire jouer le contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à jour le compte pour passer à la version payante"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index cf444a6..b4791ff 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accès à la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Appareils auditifs"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connexion établie avec les appareils auditifs"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté à LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté aux paramètres audio du téléphone"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utiliser pour les paramètres audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utiliser pour le transfert de fichiers"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utiliser comme entrée"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utiliser pour les appareils auditifs"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utiliser pour LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Associer"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ASSOCIER"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superposition à l\'écran indiquant l\'emplacement actuel du curseur"</string>
<string name="show_touches" msgid="8437666942161289025">"Indicateurs visuels"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afficher un indicateur visuel là où l\'utilisateur appuie sur l\'écran"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mises à jour de la surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Faire clignoter les endroits où des mises à jour sont effectuées"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mises à jour de fenêtres"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossible de lire du contenu sur cet appareil"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Mettez à niveau le compte pour changer"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 89145cb..c151db8 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso á SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audiófonos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Audio de baixo consumo"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audiófonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Estableceuse conexión co audio de baixo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao audio do teléfono"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilízase para o audio do teléfono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilízase para a transferencia de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilízase para a entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utilizar para audiófonos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usa esta opción para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Vincular"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"VINCULAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Superpón os datos dos toques na pantalla"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra a localización dos toques na pantalla"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ilumina as superficies de ventás ao actualizarse"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Mostrar actualizacións"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tableta"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Non se pode reproducir contido neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Cambia a conta a un plan superior para facer a modificación"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index fbcc84a..914645e 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"સિમ ઍક્સેસ"</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="58154575573984914">"શ્રવણ યંત્રો"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ઑડિયો"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"શ્રવણ યંત્રો સાથે કનેક્ટ કરેલું છે"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ઑડિયોથી કનેક્ટેડ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"મીડિયા ઑડિઓ સાથે કનેક્ટ કર્યુ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ફોન ઑડિઓ સાથે કનેક્ટ થયાં"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ફોન ઑડિઓ માટે ઉપયોગ કરો"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ફાઇલ સ્થાનાંતર માટે ઉપયોગ કરો"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ઇનપુટ માટે ઉપયોગ કરો"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"શ્રવણ યંત્રો માટે ઉપયોગ કરો"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"વર્તમાન ટચ ડેટા દર્શાવતું સ્ક્રીન ઓવરલે"</string>
<string name="show_touches" msgid="8437666942161289025">"ટૅપ બતાવો"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ટૅપ માટે વિઝ્યુઅલ પ્રતિસાદ બતાવો"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"વ્યૂના અપડેટ બતાવો"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"આ ફોન"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"આ ટૅબ્લેટ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"આ ડિવાઇસ પર ચલાવી શકતા નથી"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"સ્વિચ કરવા માટે એકાઉન્ટ અપગ્રેડ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index a123a85..f2b7ea1 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"सिम ऐक्सेस"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"एचडी ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"एचडी ऑडियो"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"कान की मशीन"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"सुनने में मदद करने वाले डिवाइस से कनेक्ट है"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio से कनेक्ट किया गया"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडियो से कनेक्ट किया गया"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फ़ोन ऑडियो से कनेक्ट किया गया"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फ़ोन ऑडियो के लिए उपयोग करें"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फ़ाइल स्थानांतरण के लिए उपयोग करें"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुट के लिए उपयोग करें"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"सुनने में मदद करने वाले डिवाइस के लिए इस्तेमाल करें"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"मौजूदा टच डेटा दिखाने वाला स्क्रीन ओवरले"</string>
<string name="show_touches" msgid="8437666942161289025">"टैप दिखाएं"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"टैप के लिए विज़ुअल फ़ीडबैक दिखाएं"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"जीपीयू व्यू के अपडेट दिखाएं"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यह फ़ोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यह टैबलेट"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"इस डिवाइस पर मीडिया नहीं चलाया जा सकता"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"प्रीमियम खाते में स्विच करने के लिए, अपना खाता अपग्रेड करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 4566cad..559fd73 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Pristup SIM-u"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezano sa Slušnim aparatima"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE_AUDIO"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano s medijskim zvukom"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa telefonskim zvukom"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Koristi za telefonski zvuk"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Koristi za prijenos datoteke"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Upotrijebi za ulaz"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Upotrijebi za Slušne aparate"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Upotrebljavajte za LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Upari"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"UPARI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Na zaslonu se prikazuju podaci o dodirima"</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dodire"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikazuju se vizualne povratne informacije za dodire"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Sve površine prozora bljeskaju pri ažuriranju"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži ažuriranja prikaza"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ne može se reproducirati ovdje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nadogradite i prebacite se"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index b9f9d79..2607e2d 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-elérés"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hallókészülékek"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Alacsony energiaszintű hangátvitel"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Hallókészülékhez csatlakoztatva"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Csatlakoztatva az alacsony energiaszintű hangátvitelhez"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Csatlakoztatva az eszköz hangjához"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Csatlakoztatva a telefon hangjához"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Felhasználás a telefon hangjához"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Felhasználás fájlátvitelre"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Használat beviteli eszközként"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Hallókészülékkel való használat"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Használat ehhez: LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Párosítás"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PÁROSÍTÁS"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"A fedvény mutatja az aktuális érintési adatokat"</string>
<string name="show_touches" msgid="8437666942161289025">"Koppintások megjelenítése"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Koppintások vizuális visszajelzésének megjelenítése"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Felületfrissítések megj."</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"A teljes ablakfelület villogjon frissítéskor."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Frissítések megjelenítése"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ez a telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ez a táblagép"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nem játszható le ezen az eszközön"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"A váltáshoz frissítse fiókját"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index de002a0..c95fb57 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Լսողական ապարատ"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Լսողական ապարատը միացված է"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Միացած է LE audio-ին"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Միացված է մեդիա աուդիոյին"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Միացված է հեռախոսի ձայնային տվյալներին"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Օգտագործել հեռախոսի աուդիոյի համար"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Օգտագործել ֆայլի փոխանցման համար"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Օգտագործել ներմուծման համար"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Օգտագործել լսողական ապարատի համար"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ հպման տվյալները"</string>
<string name="show_touches" msgid="8437666942161289025">"Ցույց տալ հպումները"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ցույց տալ հպումների տեսանելի արձագանքը"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Ցուցադրել թարմացումները"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Այս հեռախոսը"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Այս պլանշետը"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Հնարավոր չէ նվագարկել այս սարքում"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Փոխելու համար անցեք հաշվի պրեմիում տարբերակին"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index cdc297e..a56a479 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Akses SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Terhubung ke Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Terhubung ke LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Terhubung ke media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Terhubung ke audio ponsel"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gunakan untuk audio ponsel"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk transfer file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk masukan"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gunakan untuk Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Digunakan untuk LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sambungkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAMBUNGKAN"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay layar menampilkan data sentuhan saat ini"</string>
<string name="show_touches" msgid="8437666942161289025">"Tampilkan ketukan"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan efek visual untuk ketukan"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Tampilkan pembaruan permukaan"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Buat seluruh permukaan jendela berkedip saat diperbarui"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Tampilkan pembaruan tampilan"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ponsel ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat memutar di perangkat ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade akun untuk beralih"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 18acafd..0928d72 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Aðgangur að SIM-korti"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-hljóð: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-hljóð"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Heyrnartæki"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-hljóð"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Tengt við heyrnartæki"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Tengt við LE-hljóð"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Tengt við hljóðspilun efnis"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Tengt við hljóð símans"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Nota fyrir hljóð símans"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Nota við skráaflutning"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Nota fyrir inntak"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Nota fyrir heyrnartæki"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Nota fyrir LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Para"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PARA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skjáyfirlögn sem sýnir rauntímagögn um snertingar"</string>
<string name="show_touches" msgid="8437666942161289025">"Sýna snertingar"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Sýna snertingar myndrænt"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Sýna yfirborðsuppfærslur"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Láta allt yfirborð glugga blikka við uppfærslu"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Sýna uppfærslur yfirlits"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Þessi sími"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Þessi spjaldtölva"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ekki er hægt að spila í þessu tæki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppfærðu reikninginn til að skipta"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 7e84c5a..ae19c41 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Accesso alla SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Apparecchi acustici"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connessione con gli apparecchi acustici stabilita"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connesso a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Collegato ad audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Collegato ad audio telefono"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usa per audio telefono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usa per trasferimento file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizza per l\'input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utilizza per gli apparecchi acustici"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usa per LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Accoppia"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ACCOPPIA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay schermo che mostra i dati touch correnti"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostra tocchi"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostra feedback visivi per i tocchi"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Aggiornamenti superficie"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fai lampeggiare le superfici delle finestre quando si aggiornano"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Aggiornam. visualizzazione"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo telefono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Questo tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Impossibile riprodurre su questo dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Esegui l\'upgrade dell\'account per cambiare"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c772f37..6ba7aa4 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"מכשירי שמיעה"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"מחובר אל מכשירי שמיעה"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"מחובר אל LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"מחובר לאודיו של מדיה"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"מחובר לאודיו של הטלפון"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"השתמש עבור האודיו של הטלפון"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"לצורך העברת קבצים"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"שימוש כקלט"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"שימוש בשביל מכשירי שמיעה"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"שכבת-על של המסך המציגה את נתוני המגע הנוכחיים"</string>
<string name="show_touches" msgid="8437666942161289025">"הצגת הקשות"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"הצגת משוב ויזואלי להקשות"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"הצגת עדכונים של התצוגה"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"הטלפון הזה"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"הטאבלט הזה"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"הרמקול של אביזר העגינה"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"לא ניתן להפעיל במכשיר"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"יש לשדרג חשבון כדי לעבור"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a459abf..a4230fc 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"補聴器"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"補聴器に接続"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio に接続"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"メディアの音声に接続"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"携帯電話の音声に接続"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"携帯電話の音声に使用"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ファイル転送に使用"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"入力に使用"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"補聴器に使用"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"現在のタップデータをオーバーレイ表示する"</string>
<string name="show_touches" msgid="8437666942161289025">"タップを表示"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"タップを視覚表示する"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"画面の更新を表示"</string>
@@ -551,7 +558,7 @@
<skip />
<!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
<skip />
- <string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string>
+ <string name="media_transfer_this_phone" msgid="7194341457812151531">"このデバイス"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"このデバイスでは再生できません"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"アカウントを更新して切り替えてください"</string>
<string name="media_output_status_not_support_downloads" msgid="4523828729240373315">"再生不可: ダウンロードしたコンテンツ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 147512b..50447d7 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"სმენის მოწყობილობები"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-აუდიო"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"დაკავშირებულია სმენის მოწყობილობებთან"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"დაკავშირებულია LE აუდიოსთან"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"დაკავშირებულია აუდიო მულტიმედიურ სისტემასთან"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"დაკავშირებულია ტელეფონის აუდიო მოწყობილობასთან"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"გამოიყენეთ ტელეფონის აუდიომოწყობილობაში"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ფაილების ტრანსფერისათვის გამოყენება"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"შეტანისთვის გამოყენება"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"გამოყენება სმენის მოწყობილობებისთვის"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ეკრანის გადაფარვა შეხების მონაცემების ჩვენებით"</string>
<string name="show_touches" msgid="8437666942161289025">"შეხებების ჩვენება"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"შეხებებისთვის ვიზუალური უკუკავშირის ჩვენება"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"განახლებების ჩვენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 83388a0..d57bedb 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -84,7 +84,7 @@
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Ажыратылған"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Ажыратылуда…"</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"Жалғауда..."</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"Қосылып жатыр..."</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> жалғанды"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Жұптасып жатыр..."</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> жалғанды (телефонсыз)"</string>
@@ -114,9 +114,11 @@
<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="58154575573984914">"Есту аппараттары"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Есту аппараттарына жалғанған"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio-ға жалғанды."</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиосына жалғанған"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосына қосылған"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Телефон аудиосы үшін қолдану"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файлды жіберу үшін қолдану"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Кіріс үшін қолдану"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Есту аппараттары үшін пайдалану"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Экран бетіне түртілген элемент дерегі көрсетіледі"</string>
<string name="show_touches" msgid="8437666942161289025">"Түрту қимылын көрсету"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Түрту қимылын экраннан көрсету"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Көріністің жаңарғанын көрсету"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Осы телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Осы планшет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Қондыру динамигі"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Осы құрылғыда ойнату мүмкін емес."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Ауысу үшін аккаунтты жаңартыңыз."</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 0e470f5..a3f9ac8 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -99,7 +99,7 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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_active_no_battery_level" msgid="4155462233006205630">"សកម្ម"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"សកម្មខាងឆ្វេងតែប៉ុណ្ណោះ"</string>
+ <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>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"សំឡេងមេឌៀ"</string>
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ការចូលដំណើរការស៊ីម"</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="58154575573984914">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"បានភ្ជាប់ទៅឧបករណ៍ជំនួយការស្ដាប់"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"បានភ្ជាប់ទៅ LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"បានភ្ជាប់ទៅអូឌីយ៉ូមេឌៀ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"តភ្ជាប់ទៅអូឌីយ៉ូទូរស័ព្ទ"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ប្រើសម្រាប់អូឌីយ៉ូទូរស័ព្ទ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ប្រើសម្រាប់ផ្ទេរឯកសារ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ប្រើសម្រាប់បញ្ចូល"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ប្រើសម្រាប់ឧបករណ៍ជំនួយការស្តាប់"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"អេក្រង់ត្រួតគ្នាបង្ហាញទិន្នន័យប៉ះបច្ចុប្បន្ន"</string>
<string name="show_touches" msgid="8437666942161289025">"បង្ហាញការចុច"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"បង្ហាញដានចុច នៅពេលចុច"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"បង្ហាញបច្ចុប្បន្នភាពទិដ្ឋភាព"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ថេប្លេតនេះ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបករណ៍បំពងសំឡេងដែលមានជើងភ្ជាប់"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ឧបករណ៍ដែលបានភ្ជាប់"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"មិនអាចចាក់នៅលើឧបករណ៍នេះបានទេ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ដំឡើងកម្រិតគណនី ដើម្បីប្ដូរ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 9b05c6e..70ca323 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ಸಿಮ್ ಆ್ಯಕ್ಸೆಸ್"</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="58154575573984914">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ಆಡಿಯೋ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ಶ್ರವಣ ಸಾಧನಗಳಿಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ಆಡಿಯೋಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ಮಾಧ್ಯಮ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ಫೋನ್ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ಫೋನ್ ಆಡಿಯೋಗಾಗಿ ಬಳಕೆ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ಫೈಲ್ ವರ್ಗಾವಣೆಗಾಗಿ ಬಳಸು"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ಇನ್ಪುಟ್ಗಾಗಿ ಬಳಸು"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ಶ್ರವಣ ಸಾಧನಗಳಿಗಾಗಿ ಬಳಸಿ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ಪ್ರಸ್ತುತ ಸ್ಪರ್ಶ ಡೇಟಾ ತೋರಿಸುವ ಪರದೆಯ ಓವರ್ಲೇ"</string>
<string name="show_touches" msgid="8437666942161289025">"ಟ್ಯಾಪ್ಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ಟ್ಯಾಪ್ಗಳಿಗೆ ದೃಶ್ಯ ಪ್ರತಿಕ್ರಿಯೆ ತೋರಿಸು"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"\'ಅಪ್ಡೇಟ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ\' ತೋರಿಸಿ"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ಈ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ಬದಲಾಯಿಸಲು ಖಾತೆಯನ್ನು ಅಪ್ಗ್ರೇಡ್ ಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 273176c..32f86a1 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"보청기"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE 오디오"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"보청기에 연결됨"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE 오디오에 연결됨"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"미디어 오디오에 연결됨"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"휴대전화 오디오에 연결됨"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"휴대전화 오디오에 사용"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"파일 전송에 사용"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"입력에 사용"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"보청기로 사용"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"현재 터치 데이터 오버레이 표시"</string>
<string name="show_touches" msgid="8437666942161289025">"탭한 항목 표시"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"탭한 항목에 대해 시각적인 피드백 표시"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"보기 업데이트 표시"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"이 휴대전화"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"태블릿"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"이 기기에서 재생할 수 없음"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"전환하려면 계정을 업그레이드하세요."</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index e2495d0..111b804 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Угуу аппараттары"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Угуу аппараттарына туташып турат"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудио менен туташты"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиого туташты"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосуна туташты"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Телефон аудиосу үчүн колдонулсун"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файл өткөрүү үчүн колдонулсун"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Киргизүү үчүн колдонулсун"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Угуу аппараттары үчүн колдонуу"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -231,7 +234,7 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Ката"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн мүчүлүштүктөрдү Wi-Fi аркылуу аныктоону күйгүзүңүз"</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>
@@ -248,7 +251,7 @@
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Түзмөк бир тармакка туташып турушу керек."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR кодду скандап, түзмөктү Wi‑Fi аркылуу жупташтырыңыз"</string>
<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_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Түзмөк жупташтырылган жок. QR код туура эмес же түзмөк бир тармакка туташпай турат."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP дарек жана порт"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR кодду скандоо"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR кодду скандап, түзмөктү Wi‑Fi аркылуу жупташтырыңыз"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Басылган жерлер жана жаңсоолор экранда көрүнүп турат"</string>
<string name="show_touches" msgid="8437666942161289025">"Басылган жерлерди көрсөтүү"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Экранда басылган жерлер көрүнүп турат"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Жаңыртууларды көрсөтүү"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ушул телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ушул планшет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекети үчүн динамик"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Бул түзмөктө ойнотууга болбойт"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Премиум аккаунтка которулуу керек"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 25466d4..beca19e 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"ອຸປະກອນຊ່ວຍຟັງ"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"ສຽງ LE"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ເຊື່ອມຕໍ່ຫາອຸປະກອນຊ່ວຍຟັງແລ້ວ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ເຊື່ອມຕໍ່ຫາສຽງ LE ແລ້ວ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ເຊື່ອມຕໍ່ກັບສື່ດ້ານສຽງແລ້ວ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ເຊື່ອມຕໍ່ກັບສຽງໂທລະສັບແລ້ວ"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ໃຊ້ສຳລັບລະບົບສຽງຂອງໂທລະສັບ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ໃຊ້ເພື່ອໂອນຍ້າຍໄຟລ໌"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ໃຊ້ສຳລັບການປ້ອນຂໍ້ມູນ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ໃຊ້ສຳລັບອຸປະກອນຊ່ວຍຟັງ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ການວາງຊ້ອນໜ້າຈໍກຳລັງສະແດງຂໍ້ມູນການສຳຜັດໃນປັດຈຸບັນ"</string>
<string name="show_touches" msgid="8437666942161289025">"ສະແດງການແຕະ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ສະແດງຄໍາຕິຊົມທາງຮູບພາບສຳລັບການແຕະ"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"ສະແດງອັບເດດມຸມມອງ"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ແທັບເລັດນີ້"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ຫຼິ້ນຢູ່ອຸປະກອນນີ້ບໍ່ໄດ້"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ອັບເກຣດບັນຊີເພື່ອສະຫຼັບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index ff9f1c2..6307ff3 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM prieiga"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD garsas: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD garsas"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Klausos aparatai"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Prisijungta prie klausos aparatų"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Prisijungta prie „LE Audio“"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Prijungta prie medijos garso įrašo"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Prijungta prie telefono garso"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Naudoti telefono garso įrašui"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Naudoti failų perkėlimui"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Naudoti įvedant"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Naudoti su klausos aparatais"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Naudoti LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Susieti"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SUSIETI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekrano perdanga rodo dabartinius lietimo duomenis"</string>
<string name="show_touches" msgid="8437666942161289025">"Rodyti palietimus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Rodyti vaizdinius palietimų atsiliepimus"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Rodyti paviršiaus naujin."</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Naujinant mirginti visus langų paviršius"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Rodyti rodinių naujinius"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis telefonas"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetinis kompiuteris"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Negalima leisti šiame įrenginyje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Jei norite perjungti, naujovinkite paskyrą"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 9105153..880d7a4 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Piekļuve SIM kartei"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Dzirdes aparāti"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Izveidots savienojums ar dzirdes aparātiem"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Izveidots savienojums ar LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Savienots ar multivides audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Savienots ar tālruņa audio"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Izmantot tālruņa skaņai"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Izmantot faila pārsūtīšanai"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Izmantot ievadei"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Izmantot dzirdes aparātiem"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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_all_caps" msgid="2734383073450506220">"SAVIENOT PĀRĪ"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekrāna pārklājums ar aktuāliem pieskāriena datiem"</string>
<string name="show_touches" msgid="8437666942161289025">"Rādīt pieskārienus"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Rādīt vizuālo reakciju pēc pieskārieniem"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Rādīt virsmas atjauninājumus WL: 294"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Atjaunināt visa loga virsmas, kad tās tiek atjauninātas WL: 294"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Rādīt skat. atjaunin."</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis tālrunis"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetdators"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nevar atskaņot šajā ierīcē."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Lai pārslēgtu, jauniniet kontu"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0005ec5..7362c67 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Слушни помагала"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-аудио"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Поврзано со слушни помагала"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Поврзано на LE-аудио"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Поврзан со аудио на медиуми"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Поврзан со аудио на телефон"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Користи за аудио на телефон"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Користи за пренос на датотеки"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Користи за внес"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Користи за слушни помагала"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Прекривката на екран ги покажува тековните податоци на допир"</string>
<string name="show_touches" msgid="8437666942161289025">"Прикажувај допири"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Прикажувај визуелни повратни информации за допири"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Покажувај ажурирања на приказот"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Пред малку"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овој телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овој таблет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не може да се пушти на уредов"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надградете ја сметката за да се префрлите"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 12d6e52..1e7ef2b 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"സിം ആക്സസ്"</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="58154575573984914">"ശ്രവണ സഹായികൾ"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ഓഡിയോ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ശ്രവണ സഹായികളിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ഓഡിയോയിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"മീഡിയ ഓഡിയോയിലേക്ക് കണക്റ്റുചെയ്തു"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ഫോൺ ഓഡിയോയിൽ കണക്റ്റുചെയ്തു"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ഫോൺ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ഫയൽ കൈമാറ്റത്തിനായി ഉപയോഗിക്കുന്നു"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ഇൻപുട്ടിനായി ഉപയോഗിക്കുക"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ശ്രവണ സഹായികൾക്കായി ഉപയോഗിക്കുക"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"സ്ക്രീൻ ഓവർലേ നിലവിലെ ടച്ച് ഡാറ്റ ദൃശ്യമാക്കുന്നു"</string>
<string name="show_touches" msgid="8437666942161289025">"ടാപ്പുകൾ കാണിക്കുക"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ടാപ്പുകൾക്ക് ദൃശ്യ ഫീഡ്ബാക്ക് കാണിക്കുക"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"\'അപ്ഡേറ്റുകൾ കാണുക\' കാണിക്കുക"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ഈ ടാബ്ലെറ്റ്"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്പീക്കർ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്റ്റ് ചെയ്ത ഉപകരണം"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ഈ ഉപകരണത്തിൽ പ്ലേ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"അക്കൗണ്ട് മാറാൻ അപ്ഗ്രേഡ് ചെയ്യുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index d2e03f2..a77c07f 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Сонсголын төхөөрөмж"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Аудио"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Сонсголын төхөөрөмжтэй холбосон"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудионд холбогдсон"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиод холбогдсон"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Утасны аудид холбогдсон"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Утасны аудиод ашиглах"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Файл дамжуулахад ашиглах"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Оруулахад ашиглах"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Сонсголын төхөөрөмжид ашиглах"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_АУДИОНД ашиглах"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Хослуулах"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ХОСЛУУЛАХ"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Дэлгэцийн давхаргаар одоогийн хүрэлтийн өгөгдлийг харуулж байна"</string>
<string name="show_touches" msgid="8437666942161289025">"Товшилтыг харуулах"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Товшилтын визуал хариу үйлдлийг харуулах"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Шинэчлэлт харахыг харуулах"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Энэ утас"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Энэ таблет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Энэ төхөөрөмжид тоглуулах боломжгүй"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Сэлгэхийн тулд бүртгэлийг сайжруулна уу"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 8c2b4ae..0d62281 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"सिम अॅक्सेस"</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="58154575573984914">"श्रवणयंत्रे"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ऑडिओ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"श्रवण यंत्रांशी कनेक्ट केले आहे"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ऑडिओशी कनेक्ट केले आहे"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडिओवर कनेक्ट केले"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन ऑडिओ वर कनेक्ट केले"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फोन ऑडिओसाठी वापरा"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फाइल स्थानांतरणासाठी वापरा"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुट साठी वापरा"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"श्रवण यंत्रांसाठी वापरा"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"वर्तमान स्पर्श डेटा दर्शविणारे स्क्रीन ओव्हरले"</string>
<string name="show_touches" msgid="8437666942161289025">"टॅप दाखवा"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"टॅपसाठी व्हिज्युअल फीडबॅक दाखवा"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"व्ह्यू अपडेट दाखवा"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"हा फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"हा टॅबलेट"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"या डिव्हाइसवर प्ले करू शकत नाही"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"स्विच करण्यासाठी खाते अपग्रेड करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index e991b24..83326c7 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Akses SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Disambungkan pada Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Disambungkan kepada LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Disambungkan ke audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Disambungkan ke audio telefon"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gunakan untuk audio telefon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk pemindahan fail"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gunakan untuk Alat Bantu Dengar"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gunakan untuk LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Gandingkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"JADIKAN PASANGAN"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Tindihan skrin menunjukkan data sentuh semasa"</string>
<string name="show_touches" msgid="8437666942161289025">"Tunjukkan ketikan"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Tunjukkan maklum balas visual untuk ketikan"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Tunjuk kemaskinian permukaan"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Denyar permukaan tetingkap apabila dikemas kini"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Tunjuk kemaskinian paparan"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefon ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Tidak dapat dimainkan pada peranti ini"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Tingkatkan akaun untuk beralih"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 12bd02e..049354e 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -114,9 +114,9 @@
<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="58154575573984914">"နားကြားကိရိယာ"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"နားကြားကိရိယာ"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"နားကြားကိရိယာနှင့် ချိတ်ဆက်ပြီးပါပြီ"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"နားကြားကိရိယာနှင့် ချိတ်ဆက်ပြီးပါပြီ"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE အသံနှင့် ချိတ်ဆက်ထားသည်"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"မီဒီယာအသံအား ချိတ်ဆက်ရန်"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ဖုန်းအသံအား ချိတ်ဆက်ရန်"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ဖုန်းအသံအားအသုံးပြုရန်"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ဖိုင်လွဲပြောင်းရန်အတွက်အသုံးပြုရန်"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ထည့်သွင်းရန်အသုံးပြုသည်"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"နားကြားကိရိယာအတွက် အသုံးပြုသည်"</string>
+ <string name="bluetooth_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>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"လက်ရှိထိတွေ့မှုဒေတာကို ဖန်သားပေါ်တွင်ထပ်၍ ပြသသည်"</string>
<string name="show_touches" msgid="8437666942161289025">"တို့ခြင်းများကို ပြပါ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"တို့ခြင်းများအတွက် အမြင်ဖြင့် တုံ့ပြန်မှုပြသည်"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"မြင်ကွင်းအပ်ဒိတ်များ ပြခြင်း"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ဤဖုန်း"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ဤတက်ဘလက်"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ဤစက်ပစ္စည်းတွင် ဖွင့်၍မရပါ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ပြောင်းရန် အကောင့်အဆင့်ကိုမြှင့်ပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index b85dabb..16054fc 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Tilgang til SIM-kortet"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Høreapparater"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE-lyd"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Koblet til høreapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Koblet til LE-lyd"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Koblet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Koblet til telefonlyd"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Bruk for telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Bruk til filoverføring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Bruk for inndata"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Bruk for høreapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Bruk for LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koble til"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOBLE TIL"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Skjermoverlegg viser aktuelle berøringsdata"</string>
<string name="show_touches" msgid="8437666942161289025">"Vis trykk"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vis visuell tilbakemelding for trykk"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Vis overflateoppdateringer"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Fremhev hele vindusoverflater når de oppdateres"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Vis visningsoppdateringer"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Dette nettbrettet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan ikke spille på denne enheten"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oppgrader kontoen for å bytte"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index b4749bf..1d0b790 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"श्रवण यन्त्रहरू"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE अडियो"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"श्रवण यन्त्रहरूमा जडान गरियो"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE अडियोमा कनेक्ट गरिएको छ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मिडिया अडियोसँग जडित"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन अडियोमा जडान गरियो"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"फोन अडियोको लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"फाइल ट्रान्सफरका लागि प्रयोग गर्नुहोस्"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"इनपुटको लागि प्रयोग गर्नुहोस्"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"श्रवण यन्त्रहरूका लागि प्रयोग गर्नुहोस्"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"स्क्रिन ओभरलेले हालको टच डेटा देखाउँदै छ"</string>
<string name="show_touches" msgid="8437666942161289025">"ट्याप देखाइयोस्"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ट्यापका लागि भिजुअल प्रतिक्रिया देखाइयोस्"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यो फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यो ट्याब्लेट"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"यो डिभाइसमा मिडिया प्ले गर्न मिल्दैन"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"आफूले प्रयोग गर्न चाहेको खाता अपग्रेड गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 02cdba4..3287711 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Sim-toegang"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hoortoestellen"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met hoortoestellen"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Verbonden met LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbonden met audio van medium"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbonden met audio van telefoon"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Gebruiken voor audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gebruiken voor bestandsoverdracht"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gebruiken voor invoer"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gebruiken voor hoortoestellen"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gebruiken voor LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koppelen"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOPPELEN"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Schermoverlay met huidige aanraakgegevens"</string>
<string name="show_touches" msgid="8437666942161289025">"Tikken tonen"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Toon visuele feedback voor tikken"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Oppervlakupdates tonen"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Flash volledige vensteroppervlakken bij updates"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Weergave-updates tonen"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Deze telefoon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Deze tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan niet afspelen op dit apparaat"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Upgrade het account om te schakelen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 824119e..a78681e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -84,7 +84,7 @@
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"ବିଛିନ୍ନ ହେଲା"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"ବିଚ୍ଛିନ୍ନ କରୁଛି…"</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"ସଂଯୋଗ କରାଯାଉଛି…"</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"କନେକ୍ଟ ହେଉଛି…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"ସଂଯୁକ୍ତ ହେଲା<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"ପେୟାର କରୁଛି…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"ସଂଯୁକ୍ତ ହେଲା (ଫୋନ୍ ନୁହେଁ)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -114,9 +114,11 @@
<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="58154575573984914">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ଅଡିଓ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ଶ୍ରବଣ ଯନ୍ତ୍ରକୁ ସଂଯୋଗ ହୋଇଛି"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ଅଡିଓ ସହ କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ମିଡିଆ ଅଡିଓ ସହ ସଂଯୁକ୍ତ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ଫୋନ୍ ଅଡିଓ ସହିତ ସଂଯୁକ୍ତ"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ଫୋନ୍ ଅଡିଓ ପାଇଁ ବ୍ୟବହାର କର"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ଇନ୍ପୁଟ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ଶ୍ରବଣ ଯନ୍ତ୍ର ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -250,7 +253,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 କୋଡ୍ ସ୍କାନ୍ କରି ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଡିଭାଇସ୍ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ଦୟାକରି ଏକ ୱାଇ-ଫାଇ ନେଟୱାର୍କରେ ସଂଯୋଗ କରନ୍ତୁ"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ଡିବଗ୍, dev"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ଏବେର ଟଚ୍ ଡାଟା ଦେଖାଉଥିବା ସ୍କ୍ରୀନ୍ ଓଭର୍ଲେ"</string>
<string name="show_touches" msgid="8437666942161289025">"ଟାପ୍ ଦେଖାନ୍ତୁ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ଟାପ୍ ପାଇଁ ଭିଜୁଆଲ୍ ମତାମତ ଦେଖାନ୍ତୁ"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"ଭ୍ୟୁ ଅପଡେଟ୍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ଏହି ଟାବଲେଟ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ଏହି ଡିଭାଇସରେ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ସ୍ୱିଚ କରିବା ପାଇଁ ଆକାଉଣ୍ଟକୁ ଅପଗ୍ରେଡ କରନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 482315f..c6ed2d5 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"ਸਿਮ ਪਹੁੰਚ"</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="58154575573984914">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ਆਡੀਓ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ਮੀਡੀਆ ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ਫ਼ੋਨ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ਫ਼ੋਨ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ਇਨਪੁਟ ਲਈ ਵਰਤੋ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਲਈ ਵਰਤੋ"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ਸਕ੍ਰੀਨ ਓਵਰਲੇ ਮੌਜੂਦਾ ਸਪਰਸ਼ ਡਾਟਾ ਦਿਖਾ ਰਿਹਾ ਹੈ"</string>
<string name="show_touches" msgid="8437666942161289025">"ਟੈਪਾਂ ਦਿਖਾਓ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"ਟੈਪਾਂ ਲਈ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਤੀਕਰਮ ਦਿਖਾਓ"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"\'ਅੱਪਡੇਟ ਦੇਖੋ\' ਨੂੰ ਦਿਖਾਓ"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ਇਹ ਟੈਬਲੈੱਟ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"ਸਵਿੱਚ ਕਰਨ ਲਈ ਖਾਤੇ ਨੂੰ ਅੱਪਗ੍ਰੇਡ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 7425744..d9bdba7 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -84,7 +84,7 @@
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Rozłączono"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Rozłączanie..."</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"Łączenie..."</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"Łączę..."</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Połączono – <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Paruję…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Połączono (bez telefonu) – <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -99,8 +99,8 @@
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Urządzenie aktywne"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktywny, tylko lewa strona"</string>
- <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktywny, tylko prawa strona"</string>
+ <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>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Dźwięk multimediów"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Połączenia telefoniczne"</string>
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostęp do karty SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Dźwięk HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Dźwięk HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparaty słuchowe"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Połączono z aparatami słuchowymi"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Połączono z LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Połączono z funkcją audio multimediów"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Połączono z funkcją audio telefonu"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Użyj dla funkcji audio telefonu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Użyj do transferu plików"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Użyj do wprowadzania"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Użyj z aparatami słuchowymi"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Używaj dla LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sparuj"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SPARUJ"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Nakładka pokazująca dane o dotknięciach ekranu"</string>
<string name="show_touches" msgid="8437666942161289025">"Pokazuj dotknięcia"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Pokazuj potwierdzenie wizualne po dotknięciu"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Pokazuj zmiany powierzchni"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Podświetlaj całe aktualizowane powierzchnie okien"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Pokazuj aktualizacje widoku"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ten telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ten tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nie można odtworzyć na tym urządzeniu"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Aby przełączyć, potrzebujesz konta premium"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index e8a3966..c75a371 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usado para transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar para aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Exibir dados de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Piscar superfícies de toda a janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de exibição"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telefone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 8b9d33a..1c90419 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Ligado a aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ligado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ligado ao áudio de multimédia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ligado ao áudio do telefone"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do telefone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usar para transferência de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar para aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sincr."</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Apresentar dados atuais de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Destacar a superfície da janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de vistas"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telemóvel"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregam."</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Atualize a conta para mudar"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index e8a3966..c75a371 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usado para transferência de arquivo"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar para aparelhos auditivos"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parear"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PAREAR"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Exibir dados de toque"</string>
<string name="show_touches" msgid="8437666942161289025">"Mostrar toques"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Mostrar feedback visual para toques"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Mostrar superfície atualizada"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Piscar superfícies de toda a janela ao atualizar"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ver atualizações de exibição"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telefone"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Não é possível reproduzir neste dispositivo"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Faça upgrade da conta para trocar"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 244dc6f..cf6e0fe 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acces la SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparate auditive"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectat la aparatul auditiv"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectat la LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectat la profilul pentru conținut media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectat la componenta audio a telefonului"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Folosește pentru componenta audio a telefonului"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Folosește pentru transferul de fișiere"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Folosește pentru introducere date"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Folosește pentru aparatele auditive"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Folosește pentru LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Asociază"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"CONECTEAZĂ"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Suprapunere care indică date curente pt. atingeri"</string>
<string name="show_touches" msgid="8437666942161289025">"Afișează atingerile"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Afișează feedbackul vizual pentru atingeri"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Actualizări suprafețe"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Iluminarea întregii fereastre la actualizare"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Afiș. actualizări ecran"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Această tabletă"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nu se poate reda pe acest dispozitiv"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Fă upgrade contului pentru a comuta"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 321fe6f..35cf90b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Доступ к SIM-карте"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD Audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слуховые аппараты"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Слуховой аппарат подключен"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Подключено к LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Подключено к мультимедийному аудиоустройству"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Подключено к аудиоустройству телефона"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Использовать для аудиоустройства телефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Используется для передачи файлов"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Использовать для ввода"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Использовать для слухового аппарата"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Показывать данные касаний и жестов"</string>
<string name="show_touches" msgid="8437666942161289025">"Показывать нажатия"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Визуальный отклик при нажатии"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Показывать обнов. экрана"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Этот смартфон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Этот планшет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Невозможно воспроизвести на этом устройстве."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Для переключения требуется премиум-аккаунт"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 400a6e5c..517e8f5 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"ශ්රවණාධාරක"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ශ්රව්ය"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ශ්රවණාධාරක වෙත සම්බන්ධ කළා"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ශ්රව්ය වෙත සම්බන්ධ විය"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"මාධ්ය ශ්රව්යට සම්බන්ධ විය"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"දුරකතනයේ ශ්රව්යට සම්බන්ධ විය"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"දුරකථන ශ්රව්ය සඳහා භාවිතා කෙරේ"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ගොනු හුවමාරුව සඳහා භාවිතා කරන්න"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ආදානය සඳහා භාවිතා කරන්න"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ශ්රවණාධාර සඳහා භාවිත කරන්න"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"තිර උඩැතිරිය වර්තමාන ස්පර්ශ දත්ත පෙන්වයි"</string>
<string name="show_touches" msgid="8437666942161289025">"තට්ටු කිරීම් පෙන්වන්න"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"තට්ටු කිරීම් සඳහා දෘශ්ය ප්රතිපෝෂණ පෙන්වන්න"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"නැරඹීම් යාවත්කාලීන පෙන්වන්න"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"මෙම ටැබ්ලටය"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"මෙම උපාංගය මත ධාවනය කළ නොහැක"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"මාරු වීමට ගිණුම උත්ශ්රේණි කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 9806d59..5d1107e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Prístup k SIM karte"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Načúvadlá"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Pripojené k načúvadlám"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Pripojené k systému LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Pripojené ku zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Pripojené ku zvuku telefónu"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Použiť pre zvuk telefónu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Použiť na prenos súborov"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Použiť pre vstup"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Použiť pre načúvadlá"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Používať s profilom LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Párovať"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PÁROVAŤ"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Zobraziť prekryvnú vrstvu s aktuálnymi údajmi o klepnutiach"</string>
<string name="show_touches" msgid="8437666942161289025">"Zobrazovať klepnutia"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Vizuálne znázorňovať klepnutia"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Ukazovať obnovenia obsahu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Rozblikať obsah okna pri aktualizácii"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ukazovať obnovenia zobrazenia"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefón"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"V tomto zariadení sa nedá prehrávať obsah"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Inovujte účet a prejdite naň"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 86cb46d..e1c9c73 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostop do kartice SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Zvok visoke kakovosti"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni pripomočki"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE zvok"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezava s slušnimi pripomočki je vzpostavljena"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezan s profilom za predstavnostni zvok"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezava s profilom za zvok telefona vzpostavljena"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Uporabi za zvok telefona"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Uporabi za prenos datotek"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Uporabi za vnos"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Uporabi za slušne pripomočke"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Uporaba za profil LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Seznani"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SEZNANI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Prekrivanje zaslona prikazuje trenutni dotik."</string>
<string name="show_touches" msgid="8437666942161289025">"Prikaži dotike"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Prikaži vizualne povratne informacije za dotike."</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Pokaži posodob. površine"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ob posodobitvi osveži celotne površine oken."</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Prikaži posodob. pogleda"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ta telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ta tablični računalnik"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ni mogoče predvajati v tej napravi."</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Za preklop je potrebna nadgradnja računa"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index c2cecebb..373e055 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Qasje në kartën SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparatet e dëgjimit"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Lidhur me aparatet e dëgjimit"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"U lidh me audion LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"U lidh me audion e medias"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"U lidh me audion e telefonit"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Përdor për audion e telefonit"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Përdor për transferimin e skedarëve"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Përdore për hyrjen"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Përdore për aparatet e dëgjimit"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Përdor për LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Çifto"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ÇIFTO"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Mbivendosja e ekranit tregon të dhënat e prekjes"</string>
<string name="show_touches" msgid="8437666942161289025">"Shfaq trokitjet"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Shfaq reagimet vizuale për trokitjet"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Shfaq përditësimet e sipërfaqes"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ndriço të gjitha sipërfaqet e dritares kur ato të përditësohen"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Shfaq përditësimet e pamjes"</string>
@@ -455,7 +462,7 @@
<string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Duhet të zgjasë deri në rreth <xliff:g id="TIME">%1$s</xliff:g> bazuar në përdorimin tënd"</string>
<string name="power_discharge_by" msgid="4113180890060388350">"Duhet të zgjasë deri në rreth <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">"Duhet të zgjasë deri në rreth <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Deri në <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Deri në: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Bateria mund të mbarojë deri në <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Më pak se <xliff:g id="THRESHOLD">%1$s</xliff:g> e mbetur"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Më pak se <xliff:g id="THRESHOLD">%1$s</xliff:g> e mbetur (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ky telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ky tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Nuk mund të luhet në këtë pajisje"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Përmirëso llogarinë për të ndryshuar"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 041b515a..b81f18e 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"Слушни апарати"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Повезано са слушним апаратима"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Повезано са LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Повезано са звуком медија"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Повезано са звуком телефона"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Коришћење за аудио телефона"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Коришћење за пренос датотека"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Користи за улаз"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Користи за слушне апарате"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Преклопни елемент са тренутним подацима о додиру"</string>
<string name="show_touches" msgid="8437666942161289025">"Приказуј додире"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Приказује визуелне повратне информације за додире"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Прикажи ажурирања приказа"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овај телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овај таблет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можете да пустите на овом уређају"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Надоградите налог ради пребацивања"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 453f2cf..2915d39 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM-åtkomst"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ljud: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ljud"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hörapparater"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Ansluten till hörapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ansluten till LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ansluten till medialjud"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ansluten till telefonens ljud"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Använd för telefonens ljud"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Använd för filöverföring"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Använd för inmatning"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Använd med hörapparater"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Använd för LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Parkoppla"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"PARKOPPLA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Överlägg på skärmen med aktuella skärmtryck"</string>
<string name="show_touches" msgid="8437666942161289025">"Visa tryck"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Visa visuell feedback för tryck"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Visa ytuppdateringar"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Hela fönstret blinkar vid uppdatering"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Visa visningsuppdatering"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Den här telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Den här surfplattan"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Kan inte spelas på denna enhet"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Uppgradera kontot för att byta"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d6fdc1e..0ec1278 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Ufikiaji wa SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Sauti ya HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Sauti ya HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Vifaa vya Kusaidia Kusikia"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Imeunganishwa kwenye Vifaa vya Kusaidia Kusikia"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Imeunganishwa kwenye LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Imeunganishwa kwenye sikika ya njia ya mawasiliano"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Imeunganishwa kwenye sauti ya simu"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Tumia kwa sauti ya simu"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Tumia kwa hali faili"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Tumia kwa kuingiza"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Tumia kwenye Vifaa vya Kusaidia Kusikia"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Tumia kwa ajili ya LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Oanisha"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"OANISHA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Kuegeshwa kwa skrini ikionyesha data ya mguso ya sasa"</string>
<string name="show_touches" msgid="8437666942161289025">"Onyesha unapogusa"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Onyesha ishara za kuthibitisha unapogusa"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Onyesha masasisho ya sehemu"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Angaza dirisha lote zitakaposasisha"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Onyesha taarifa za kuonekana"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Simu hii"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Kompyuta kibao hii"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Huwezi kucheza maudhui kwenye kifaa hiki"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Pata toleo jipya la akaunti ili ubadilishe"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index fa39a71..7e2d74e 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"சிம் அணுகல்"</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="58154575573984914">"செவித்துணை கருவிகள்"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE ஆடியோ"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"செவித்துணை கருவிகளுடன் இணைக்கப்பட்டது"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ஆடியோவுடன் இணைக்கப்பட்டுள்ளது"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ஃபைல் பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"உள்ளீட்டுக்குப் பயன்படுத்து"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"செவித்துணை கருவிகளுக்குப் பயன்படுத்தவும்"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"திரையின் மேல் அடுக்கானது தற்போது தொடப்பட்டிருக்கும் தரவைக் காண்பிக்கிறது"</string>
<string name="show_touches" msgid="8437666942161289025">"தட்டல்களைக் காட்டு"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"தட்டல்களின் போது காட்சி அறிகுறிகளைக் காட்டும்"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"வியூ அப்டேட்ஸைக் காட்டு"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"இந்த மொபைல்"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"இந்த டேப்லெட்"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"இந்தச் சாதனத்தில் பிளே செய்ய முடியவில்லை"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"மாற்ற, கணக்கை மேம்படுத்துங்கள்"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index db2307d..d250352 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -66,7 +66,7 @@
<string-array name="bt_hci_snoop_log_filters_entries">
<item msgid="195768089203590086">"ACLహెడర్లను మాత్రమే వదిలివేయండి"</item>
<item msgid="2776218217644557831">"A2DP మీడియా ప్యాకెట్లను ఫిల్టర్ చేయండి"</item>
- <item msgid="8163235976612675092">"RFCOMM ఛానెల్ని ఫిల్టర్ చేయండి"</item>
+ <item msgid="8163235976612675092">"RFCOMM ఛానెల్ను ఫిల్టర్ చేయండి"</item>
</string-array>
<string-array name="bt_hci_snoop_log_profile_filter_entries">
<item msgid="3961868665260627524">"డిజేబుల్ చేయండి"</item>
@@ -269,10 +269,10 @@
<string-array name="app_process_limit_entries">
<item msgid="794656271086646068">"స్టాండర్డ్ పరిమితి"</item>
<item msgid="8628438298170567201">"నేపథ్య ప్రాసెస్లు లేవు"</item>
- <item msgid="915752993383950932">"గరిష్టంగా 1 ప్రాసెస్"</item>
- <item msgid="8554877790859095133">"గరిష్టంగా 2 ప్రాసెస్లు"</item>
- <item msgid="9060830517215174315">"గరిష్టంగా 3 ప్రాసెస్లు"</item>
- <item msgid="6506681373060736204">"గరిష్టంగా 4 ప్రాసెస్లు"</item>
+ <item msgid="915752993383950932">"గరిష్ఠంగా 1 ప్రాసెస్"</item>
+ <item msgid="8554877790859095133">"గరిష్ఠంగా 2 ప్రాసెస్లు"</item>
+ <item msgid="9060830517215174315">"గరిష్ఠంగా 3 ప్రాసెస్లు"</item>
+ <item msgid="6506681373060736204">"గరిష్ఠంగా 4 ప్రాసెస్లు"</item>
</string-array>
<string-array name="usb_configuration_titles">
<item msgid="3358668781763928157">"ఛార్జింగ్"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index e8336f0..6d2449c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -114,9 +114,9 @@
<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="58154575573984914">"వినికిడి మద్దతు ఉపకరణాలు"</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="8191273236809964030">"వినికిడి మద్దతు ఉపకరణాలకు కనెక్ట్ చేయబడింది"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"వినికిడి పరికరాలకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ఆడియోకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"మీడియా ఆడియోకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ఫోన్ ఆడియోకు కనెక్ట్ చేయబడింది"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ఫోన్ ఆడియో కోసం ఉపయోగించండి"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ఫైల్ బదిలీ కోసం ఉపయోగించండి"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ఇన్పుట్ కోసం ఉపయోగించండి"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"వినికిడి మద్దతు ఉపకరణాలకు ఉపయోగించండి"</string>
+ <string name="bluetooth_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>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"ప్రస్తుత టచ్ డేటాను చూపుతోన్న స్క్రీన్"</string>
<string name="show_touches" msgid="8437666942161289025">"నొక్కినవి చూపు"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"నొక్కినప్పుడు దృశ్యపరమైన ప్రతిస్పందన చూపు"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"వీక్షణ అప్డేట్లను చూపు"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ఈ ఫోన్"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ఈ టాబ్లెట్"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్టర్నల్ పరికరం"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"ఈ పరికరంలో ప్లే చేయడం సాధ్యపడదు"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"మారడానికి ఖాతాను అప్గ్రేడ్ చేయండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 8335cba..1e1cbfc 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"การเข้าถึงซิม"</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="58154575573984914">"เครื่องช่วยฟัง"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"เชื่อมต่อกับเครื่องช่วยฟังแล้ว"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"เชื่อมต่อกับ LE Audio แล้ว"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"เชื่อมต่อกับระบบเสียงของสื่อแล้ว"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"เชื่อมต่อกับระบบเสียงของโทรศัพท์แล้ว"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ใช้สำหรับระบบเสียงของโทรศัพท์"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ใช้สำหรับการโอนไฟล์"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ใช้สำหรับการป้อนข้อมูล"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ใช้สำหรับเครื่องช่วยฟัง"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"การวางซ้อนหน้าจอที่แสดงข้อมูลการแตะในปัจจุบัน"</string>
<string name="show_touches" msgid="8437666942161289025">"แสดงการแตะ"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"แสดงผลตอบสนองแบบภาพเมื่อแตะ"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"แสดงการอัปเดตมุมมอง"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"แท็บเล็ตเครื่องนี้"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นวางลำโพง"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"เล่นในอุปกรณ์นี้ไม่ได้"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"อัปเกรดบัญชีเพื่อเปลี่ยน"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index dd729de..f0cb867 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Access sa SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Mga Hearing Aid"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Nakakonekta sa Mga Hearing Aid"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Nakakonekta sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Konektado sa media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Nakakonekta sa audio ng telepono"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Ginagamit para sa audio ng telepono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Ginagamit para sa paglilipat ng file"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gamitin para sa input"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gamitin para sa Mga Hearing Aid"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Gamitin para sa LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Ipares"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"IPARES"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Overlay ng screen na nagpapakita ng touch data"</string>
<string name="show_touches" msgid="8437666942161289025">"Ipakita ang mga pag-tap"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ipakita ang visual na feedback para sa mga pag-tap"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Ipakita update sa surface"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"I-flash ang buong window surface kapag nag-update"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Ipakita update ng view"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ang teleponong ito"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ang tablet na ito"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Hindi ma-play sa device na ito"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"I-upgrade ang account para lumipat"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index a2417ed..6b7e699 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM Erişimi"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ses: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ses"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"İşitme Cihazları"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"İşitme Cihazlarına Bağlandı"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio\'ya bağlandı"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Medya sesine bağlanıldı"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon sesine bağlandı"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Telefon sesi için kullan"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Dosya aktarımı için kullan"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Giriş için kullan"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"İşitme Cihazları için kullan"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO kullan"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Eşle"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"EŞLE"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Mevcut dokunmatik verilerini gösteren yer paylaşımı"</string>
<string name="show_touches" msgid="8437666942161289025">"Dokunmayı göster"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Dokunmalarda görsel geri bildirim göster"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Yüzey güncellemelerini göster"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Güncellenirken tüm pencere yüzeylerini yakıp söndür"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Görünüm güncellemelerini göster"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu tablet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu cihazda oynatılamıyor"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Geçiş yapmak için hesabı yükseltin"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index b5c31f4..a5296ed 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -107,16 +107,18 @@
<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="4262303387989406171">"Доступ до контактів та історії дзвінків"</string>
+ <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Доступ до контактів і історії викликів"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Використовуйте, щоб надсилати контакти й історію викликів"</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="58154575573984914">"Слухові апарати"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Підключено до слухових апаратів"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Підключено до LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Підключено до аудіоджерела"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Підключено до звуку телеф."</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Викор. для звуку тел."</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Викор. для перед. файлів"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Викор. для введ."</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Використовувати для слухових апаратів"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Показувати на екрані жести й натискання"</string>
<string name="show_touches" msgid="8437666942161289025">"Показувати дотики"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Показувати візуальну реакцію на торкання"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"Показувати оновлення областей"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Цей телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Цей планшет"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Не можна відтворювати тут"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Потрібний платний обліковий запис"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index fea22aa5..944726a 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"سماعتی آلات"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE آڈیو"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"سماعتی آلات سے منسلک ہے"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE آڈیو سے منسلک ہے"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"میڈیا آڈیو سے مربوط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"فون آڈیو سے مربوط"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"فون آڈیو کیلئے استعمال کریں"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"فائل منتقل کرنے کیلئے استعمال کریں"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ان پٹ کیلئے استعمال"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"سماعتی آلات کے لیے استعمال کریں"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"موجودہ ٹچ ڈیٹا دکھانے والا اسکرین اوور لے"</string>
<string name="show_touches" msgid="8437666942161289025">"تھپتھپاہٹیں دکھائیں"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"تھپتھپاہٹوں کیلئے بصری تاثرات دکھائیں"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"منظر کے اپ ڈیٹس دکھائیں"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"یہ فون"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"یہ ٹیبلیٹ"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"اس آلے پر چلایا نہیں جا سکتا"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"سوئچ کرنے کے لیے اکاؤنٹ اپ گریڈ کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 312a22e..86653a2 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -114,9 +114,9 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM kartaga kirish"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Eshitish apparatlari"</string>
+ <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Eshitish moslamalari"</string>
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Eshitish apparatlariga ulangan"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Eshitish moslamalariga ulangan"</string>
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audioga ulandi"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Audio qurilmasiga ulangan"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon karnayiga ulanildi"</string>
@@ -134,7 +134,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Dok’dan karnay sifatida foydalanish"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Fayl almashinish uchun foydalanish"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Kiritish qurilmasi sifatida foydalanish"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Eshitish apparatlari uchun foydalanish"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Eshitish moslamalari uchun foydalanish"</string>
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO uchun foydalanish"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"OK"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ULANISH"</string>
@@ -355,6 +355,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Ekranda bosilgan va tegilgan joylarni vizuallashtirish"</string>
<string name="show_touches" msgid="8437666942161289025">"Bosishlarni ko‘rsatish"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Ekranda bosilgan joylardagi nuqtalarni ko‘rsatish"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Yuza yangilanishlarini ko‘rsatish"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Yangilangandan so‘ng to‘liq oyna sirtlarini miltillatish"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Yangilash oynasini ochish"</string>
@@ -545,12 +549,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Shu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Shu planshet"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Bu qurilmada ijro etilmaydi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Oʻtish uchun hisobingizni yangilang"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b16f200..712b5ae 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Truy cập SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Âm thanh HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Âm thanh HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Thiết bị trợ thính"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Âm thanh năng lượng thấp"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Đã kết nối với Thiết bị trợ thính"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Đã kết nối với âm thanh LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Đã kết nối với âm thanh nội dung nghe nhìn"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Đã kết nối với âm thanh điện thoại"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Sử dụng cho âm thanh điện thoại"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Sử dụng để chuyển tệp"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Sử dụng để nhập"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Dùng cho Thiết bị trợ thính"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Dùng cho LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Ghép nối"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"GHÉP NỐI"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Lớp phủ màn hình hiển thị dữ liệu chạm hiện tại"</string>
<string name="show_touches" msgid="8437666942161289025">"Hiện số lần nhấn"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Hiển thị phản hồi trực quan cho các lần nhấn"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Hiện bản cập nhật giao diện"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Chuyển nhanh toàn bộ các giao diện cửa sổ khi các giao diện này cập nhật"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Hiện bản cập nhật chế độ xem"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Điện thoại này"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Máy tính bảng này"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Không phát được trên thiết bị này"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Nâng cấp tài khoản để chuyển đổi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index d266d14..d20b421 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"助听器"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE 音频"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已连接到助听器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已连接到 LE 音频"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已连接到媒体音频"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已连接到手机音频"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用于手机音频"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用于文件传输"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用于输入"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"用于助听器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"屏幕叠加层显示当前触摸数据"</string>
<string name="show_touches" msgid="8437666942161289025">"显示点按操作反馈"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"显示点按操作的视觉反馈"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"显示面 (surface) 更新"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"窗口中的面 (surface) 更新时全部闪烁"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"显示视图更新"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"这部手机"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"这台平板电脑"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"无法在此设备上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"升级帐号后才能切换"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index be7c044..f83e9c6 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM 卡存取"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"高清音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"高清音訊"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"助聽器"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已連接助聽器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連接 LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已連接媒體音頻裝置"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已連接手機耳機"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用於手機音效"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用於輸入"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"用於助聽器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"在螢幕上重疊顯示目前的觸控資料"</string>
<string name="show_touches" msgid="8437666942161289025">"顯示輕按回應"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"顯示輕按位置的視覺回應"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"顯示畫面更新"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"此手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"此平板電腦"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這部手機"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在此裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 59105e5..2aae4a8 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -114,9 +114,11 @@
<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="58154575573984914">"助聽器"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE Audio"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已連接到助聽器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連上 LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"連接至媒體音訊"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"連接至電話音訊"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"用於電話音訊"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"用於傳輸檔案"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"用於輸入"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"用於助聽器"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<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>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"在螢幕圖層上顯示目前的觸控資料"</string>
<string name="show_touches" msgid="8437666942161289025">"顯示觸控回應"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"顯示觸控位置的視覺回應"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<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">"顯示畫面更新"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"這支手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"這台平板電腦"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"無法在這部裝置上播放"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"請升級要切換的帳戶"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 87cf1f7..6a56006 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -114,9 +114,11 @@
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Ukufinyelela kwe-SIM"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Umsindo we-HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Umsindo we-HD"</string>
- <string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Izinsiza zokuzwa"</string>
+ <!-- no translation found for bluetooth_profile_hearing_aid (2607867572569689732) -->
+ <skip />
<string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Umsindo we-LE"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Kuxhumeke kwizinsiza zokuzwa"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_connected (5757754050938807276) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Kuxhunywe kumsindo we-LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ixhume emsindweni wemidiya"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ixhunywe kumsindo wefoni"</string>
@@ -134,7 +136,8 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Sebenziselwa umsindo wefoni"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Sebenziselwa ukudlulisa ifayela"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Isetshenziselwa okufakwayo"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Sebenzisa izinsiza zokuzwa"</string>
+ <!-- no translation found for bluetooth_hearing_aid_profile_summary_use_for (3374057355721486932) -->
+ <skip />
<string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Sebenzisela i-LE_AUDIO"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Bhangqa"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BHANGQA"</string>
@@ -355,6 +358,10 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Imbondela yesikrini ibonisa idatha yokuthinta yamanje"</string>
<string name="show_touches" msgid="8437666942161289025">"Bonisa amathebhu"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Bonisa izmpendulo ebukekayo ngamathebhu"</string>
+ <!-- no translation found for show_key_presses (6360141722735900214) -->
+ <skip />
+ <!-- no translation found for show_key_presses_summary (725387457373015024) -->
+ <skip />
<string name="show_screen_updates" msgid="2078782895825535494">"Buka izibuyekezo ezibonakalayo"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Khanyisa ukubonakala kwalo lonke iwindi uma libuyekezwa"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Bonisa izibuyekezo zokubuka"</string>
@@ -545,12 +552,9 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Le foni"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Le thebulethi"</string>
- <!-- no translation found for media_transfer_dock_speaker_device_name (2856219597113881950) -->
- <skip />
- <!-- no translation found for media_transfer_external_device_name (2588672258721846418) -->
- <skip />
- <!-- no translation found for media_transfer_default_device_name (4315604017399871828) -->
- <skip />
+ <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
+ <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
+ <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
<string name="media_output_status_unknown_error" msgid="5098565887497902222">"Ayikwazi ukudlala kule divayisi"</string>
<string name="media_output_status_require_premium" msgid="8411255800047014822">"Thuthukisa i-akhawunti ukuze ushintshe"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9f884b2..60bc226 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -827,9 +827,9 @@
<!-- UI debug setting: show touches location summary [CHAR LIMIT=50] -->
<string name="show_touches_summary">Show visual feedback for taps</string>
- <!-- UI debug setting: show key presses? [CHAR LIMIT=25] -->
+ <!-- UI debug setting: show key presses? [CHAR LIMIT=50] -->
<string name="show_key_presses">Show key presses</string>
- <!-- UI debug setting: show physical key presses summary [CHAR LIMIT=50] -->
+ <!-- UI debug setting: show physical key presses summary [CHAR LIMIT=150] -->
<string name="show_key_presses_summary">Show visual feedback for physical key presses</string>
<!-- UI debug setting: show where surface updates happen? [CHAR LIMIT=25] -->
@@ -934,7 +934,7 @@
<!-- UI debug setting: show all ANRs summary [CHAR LIMIT=100] -->
<string name="show_all_anrs_summary">Display App Not Responding dialog for background apps</string>
- <!-- UI debug setting: show missing channel toasts? [CHAR LIMIT=25] -->
+ <!-- UI debug setting: show missing channel toasts? [CHAR LIMIT=30] -->
<string name="show_notification_channel_warnings">Show notification channel warnings</string>
<!-- UI debug setting: show missing channel toasts summary [CHAR LIMIT=50] -->
<string name="show_notification_channel_warnings_summary">Displays on-screen warning when an app posts a notification without a valid channel</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 56f0480..0bd9384 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -107,10 +107,8 @@
&& !TextUtils.isEmpty(mPackageName)) {
RouteListingPreference routeListingPreference =
getRouteListingPreference();
- if (routeListingPreference != null) {
- Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference,
- mPreferenceItemMap);
- }
+ Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference,
+ mPreferenceItemMap);
}
}
@@ -674,9 +672,9 @@
public void onRouteListingPreferenceUpdated(
String packageName,
RouteListingPreference routeListingPreference) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference,
- mPreferenceItemMap);
+ if (TextUtils.equals(mPackageName, packageName)) {
+ Api34Impl.onRouteListingPreferenceUpdated(
+ routeListingPreference, mPreferenceItemMap);
refreshDevices();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
index e61c8f5..997d1f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
@@ -59,6 +59,7 @@
private static final String KEY_IS_ADMIN = "admin_status";
private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
"key_add_user_long_message_displayed";
+ public static final int MESSAGE_PADDING = 10;
@Retention(RetentionPolicy.SOURCE)
@IntDef({EXIT_DIALOG, INITIAL_DIALOG, GRANT_ADMIN_DIALOG,
@@ -191,6 +192,7 @@
cancelCallback.run();
clear();
});
+ mCustomDialogHelper.setMessagePadding(MESSAGE_PADDING);
mUserCreationDialog.setCanceledOnTouchOutside(true);
return mUserCreationDialog;
}
@@ -212,7 +214,6 @@
}
updateLayout();
});
- return;
}
private void updateLayout() {
@@ -234,7 +235,6 @@
}
Drawable icon = mActivity.getDrawable(R.drawable.ic_person_add);
mCustomDialogHelper.setVisibility(mCustomDialogHelper.ICON, true)
- .setVisibility(mCustomDialogHelper.TITLE, true)
.setVisibility(mCustomDialogHelper.MESSAGE, true)
.setIcon(icon)
.setButtonEnabled(true)
@@ -248,7 +248,6 @@
mGrantAdminView.setVisibility(View.VISIBLE);
mCustomDialogHelper
.setVisibility(mCustomDialogHelper.ICON, true)
- .setVisibility(mCustomDialogHelper.TITLE, true)
.setVisibility(mCustomDialogHelper.MESSAGE, true)
.setIcon(mActivity.getDrawable(R.drawable.ic_admin_panel_settings))
.setTitle(R.string.user_grant_admin_title)
@@ -262,8 +261,8 @@
case EDIT_NAME_DIALOG:
mCustomDialogHelper
.setVisibility(mCustomDialogHelper.ICON, false)
- .setVisibility(mCustomDialogHelper.TITLE, false)
.setVisibility(mCustomDialogHelper.MESSAGE, false)
+ .setTitle(R.string.user_info_settings_title)
.setNegativeButtonText(R.string.back)
.setPositiveButtonText(R.string.done);
mEditUserInfoView.setVisibility(View.VISIBLE);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
index e55d7ea..cd5f597 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
@@ -17,7 +17,6 @@
package com.android.settingslib.users;
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
@@ -31,7 +30,6 @@
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
-import android.widget.ScrollView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -41,6 +39,7 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.settingslib.utils.CustomDialogHelper;
import java.io.File;
import java.util.function.BiConsumer;
@@ -128,7 +127,7 @@
* codes to take photo/choose photo/crop photo.
*/
public Dialog createDialog(Activity activity, ActivityStarter activityStarter,
- @Nullable Drawable oldUserIcon, String defaultUserName, String title,
+ @Nullable Drawable oldUserIcon, String defaultUserName,
BiConsumer<String, Drawable> successCallback, Runnable cancelCallback) {
LayoutInflater inflater = LayoutInflater.from(activity);
View content = inflater.inflate(R.layout.edit_user_info_dialog_content, null);
@@ -160,10 +159,8 @@
userPhotoView);
}
}
- ScrollView scrollView = content.findViewById(R.id.user_info_scroll);
- scrollView.setClipToOutline(true);
mEditUserInfoDialog = buildDialog(activity, content, userNameView, oldUserIcon,
- defaultUserName, title, successCallback, cancelCallback);
+ defaultUserName, successCallback, cancelCallback);
// Make sure the IME is up.
mEditUserInfoDialog.getWindow()
@@ -181,12 +178,13 @@
}
private Dialog buildDialog(Activity activity, View content, EditText userNameView,
- @Nullable Drawable oldUserIcon, String defaultUserName, String title,
+ @Nullable Drawable oldUserIcon, String defaultUserName,
BiConsumer<String, Drawable> successCallback, Runnable cancelCallback) {
- return new AlertDialog.Builder(activity)
- .setView(content)
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ CustomDialogHelper dialogHelper = new CustomDialogHelper(activity);
+ dialogHelper
+ .setTitle(R.string.user_info_settings_title)
+ .addCustomView(content)
+ .setPositiveButton(android.R.string.ok, view -> {
Drawable newUserIcon = mEditUserPhotoController != null
? mEditUserPhotoController.getNewUserPhotoDrawable()
: null;
@@ -201,20 +199,23 @@
if (successCallback != null) {
successCallback.accept(userName, userIcon);
}
+ dialogHelper.getDialog().dismiss();
})
- .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
+ .setBackButton(android.R.string.cancel, view -> {
clear();
if (cancelCallback != null) {
cancelCallback.run();
}
- })
- .setOnCancelListener(dialog -> {
- clear();
- if (cancelCallback != null) {
- cancelCallback.run();
- }
- })
- .create();
+ dialogHelper.getDialog().dismiss();
+ });
+ dialogHelper.getDialog().setOnCancelListener(dialog -> {
+ clear();
+ if (cancelCallback != null) {
+ cancelCallback.run();
+ }
+ dialogHelper.getDialog().dismiss();
+ });
+ return dialogHelper.getDialog();
}
@VisibleForTesting
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
index de48814..5201b3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
@@ -193,6 +193,14 @@
}
/**
+ * Sets message padding of the dialog.
+ */
+ public CustomDialogHelper setMessagePadding(int dp) {
+ mDialogMessage.setPadding(dp, dp, dp, dp);
+ return this;
+ }
+
+ /**
* Sets icon of the dialog.
*/
public CustomDialogHelper setIcon(Drawable icon) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 75a8679..ce1744d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -73,6 +73,7 @@
public class InfoMediaManagerTest {
private static final String TEST_PACKAGE_NAME = "com.test.packagename";
+ private static final String TEST_PACKAGE_NAME_2 = "com.test.packagename2";
private static final String TEST_ID = "test_id";
private static final String TEST_ID_1 = "test_id_1";
private static final String TEST_ID_2 = "test_id_2";
@@ -309,7 +310,54 @@
}
@Test
- public void onRouteChanged_getAvailableRoutesWithPrefernceListExit_ordersRoutes() {
+ public void onRouteChanged_getAvailableRoutesWithPreferenceListExit_ordersRoutes() {
+ RouteListingPreference routeListingPreference = setUpPreferenceList(TEST_PACKAGE_NAME);
+ setUpSelectedRoutes(TEST_PACKAGE_NAME);
+
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(sessionInfo);
+
+ when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos);
+ when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID));
+
+ setAvailableRoutesList(TEST_PACKAGE_NAME);
+
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME,
+ routeListingPreference);
+ mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
+
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(3);
+ assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID);
+ assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4);
+ assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue();
+ assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3);
+ }
+
+ @Test
+ public void onRouteChanged_preferenceListUpdateWithDifferentPkg_notOrdersRoutes() {
+ RouteListingPreference routeListingPreference = setUpPreferenceList(TEST_PACKAGE_NAME_2);
+ setUpSelectedRoutes(TEST_PACKAGE_NAME);
+
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(sessionInfo);
+
+ when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos);
+ when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID));
+
+ setAvailableRoutesList(TEST_PACKAGE_NAME);
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME_2,
+ routeListingPreference);
+ mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
+
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(1);
+ assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID);
+ }
+
+ private RouteListingPreference setUpPreferenceList(String packageName) {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT",
Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
final List<RouteListingPreference.Item> preferenceItemList = new ArrayList<>();
@@ -325,57 +373,40 @@
RouteListingPreference routeListingPreference =
new RouteListingPreference.Builder().setItems(
preferenceItemList).setUseSystemOrdering(false).build();
- when(mRouterManager.getRouteListingPreference(TEST_PACKAGE_NAME))
+ when(mRouterManager.getRouteListingPreference(packageName))
.thenReturn(routeListingPreference);
+ return routeListingPreference;
+ }
+ private void setUpSelectedRoutes(String packageName) {
final List<MediaRoute2Info> selectedRoutes = new ArrayList<>();
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
- when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(info.getClientPackageName()).thenReturn(packageName);
when(info.isSystemRoute()).thenReturn(true);
selectedRoutes.add(info);
when(mRouterManager.getSelectedRoutes(any())).thenReturn(selectedRoutes);
-
- final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
- final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
- routingSessionInfos.add(sessionInfo);
-
- when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos);
- when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID));
-
- setAvailableRoutesList();
-
- mInfoMediaManager.mRouterManager = mRouterManager;
- mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME,
- routeListingPreference);
- mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
-
- assertThat(mInfoMediaManager.mMediaDevices).hasSize(3);
- assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue();
- assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3);
}
- private List<MediaRoute2Info> setAvailableRoutesList() {
+ private List<MediaRoute2Info> setAvailableRoutesList(String packageName) {
final List<MediaRoute2Info> availableRoutes = new ArrayList<>();
final MediaRoute2Info availableInfo1 = mock(MediaRoute2Info.class);
when(availableInfo1.getId()).thenReturn(TEST_ID_2);
- when(availableInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(availableInfo1.getClientPackageName()).thenReturn(packageName);
when(availableInfo1.getType()).thenReturn(TYPE_REMOTE_TV);
availableRoutes.add(availableInfo1);
final MediaRoute2Info availableInfo2 = mock(MediaRoute2Info.class);
when(availableInfo2.getId()).thenReturn(TEST_ID_3);
- when(availableInfo2.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(availableInfo2.getClientPackageName()).thenReturn(packageName);
availableRoutes.add(availableInfo2);
final MediaRoute2Info availableInfo3 = mock(MediaRoute2Info.class);
when(availableInfo3.getId()).thenReturn(TEST_ID_4);
- when(availableInfo3.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(availableInfo3.getClientPackageName()).thenReturn(packageName);
availableRoutes.add(availableInfo3);
- when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(
+ when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(
availableRoutes);
return availableRoutes;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
index e989ed2..b538077 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
@@ -111,13 +111,13 @@
mActivityStarter, true, null,
cancelCallback);
dialog.show();
- assertThat(dialog.findViewById(R.id.user_info_scroll).getVisibility()).isEqualTo(View.GONE);
+ assertThat(dialog.findViewById(R.id.user_info_editor).getVisibility()).isEqualTo(View.GONE);
Button next = dialog.findViewById(R.id.button_ok);
next.performClick();
((RadioButton) dialog.findViewById(R.id.grant_admin_yes)).setChecked(true);
- assertThat(dialog.findViewById(R.id.user_info_scroll).getVisibility()).isEqualTo(View.GONE);
+ assertThat(dialog.findViewById(R.id.user_info_editor).getVisibility()).isEqualTo(View.GONE);
next.performClick();
- assertThat(dialog.findViewById(R.id.user_info_scroll).getVisibility())
+ assertThat(dialog.findViewById(R.id.user_info_editor).getVisibility())
.isEqualTo(View.VISIBLE);
dialog.dismiss();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
index f760032..f595cd3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
@@ -27,7 +27,6 @@
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -108,7 +107,7 @@
@Test
public void photoControllerOnActivityResult_whenWaiting_isCalled() {
mController.createDialog(mActivity, mActivityStarter, mCurrentIcon, "test user",
- "title", null, null);
+ null, null);
mController.startingActivityForResult();
Intent resultData = new Intent();
mController.onActivityResult(0, 0, resultData);
@@ -126,9 +125,7 @@
() -> String.valueOf('A')).limit(200).collect(Collectors.joining());
final AlertDialog dialog = (AlertDialog) mController.createDialog(mActivity,
- mActivityStarter, mCurrentIcon,
- "test user", "title", null,
- null);
+ mActivityStarter, mCurrentIcon, "test user", null, null);
dialog.show();
final EditText userNameEditText = dialog.findViewById(R.id.user_name);
userNameEditText.setText(longName);
@@ -143,7 +140,7 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, mCurrentIcon, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
dialog.show();
dialog.cancel();
@@ -159,9 +156,9 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, mCurrentIcon, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
dialog.show();
- dialog.getButton(Dialog.BUTTON_NEGATIVE).performClick();
+ dialog.findViewById(R.id.button_back).performClick();
verifyNoInteractions(successCallback);
verify(cancelCallback, times(1))
@@ -176,11 +173,11 @@
Drawable oldUserIcon = mCurrentIcon;
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, oldUserIcon, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
// No change to the photo.
when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
dialog.show();
- dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+ dialog.findViewById(R.id.button_ok).performClick();
verify(successCallback, times(1))
.accept("test", oldUserIcon);
@@ -194,11 +191,11 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, null, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
// No change to the photo.
when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
dialog.show();
- dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+ dialog.findViewById(R.id.button_ok).performClick();
verify(successCallback, times(1))
.accept("test", null);
@@ -212,14 +209,14 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, mCurrentIcon, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
// No change to the photo.
when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
dialog.show();
String expectedNewName = "new test user";
EditText editText = (EditText) dialog.findViewById(R.id.user_name);
editText.setText(expectedNewName);
- dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+ dialog.findViewById(R.id.button_ok).performClick();
verify(successCallback, times(1))
.accept(expectedNewName, mCurrentIcon);
@@ -233,12 +230,12 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, mCurrentIcon, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
// A different drawable.
Drawable newPhoto = mock(Drawable.class);
when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(newPhoto);
dialog.show();
- dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+ dialog.findViewById(R.id.button_ok).performClick();
verify(successCallback, times(1))
.accept("test", newPhoto);
@@ -252,12 +249,12 @@
AlertDialog dialog = (AlertDialog) mController.createDialog(
mActivity, mActivityStarter, null, "test",
- "title", successCallback, cancelCallback);
+ successCallback, cancelCallback);
// A different drawable.
Drawable newPhoto = mock(Drawable.class);
when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(newPhoto);
dialog.show();
- dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+ dialog.findViewById(R.id.button_ok).performClick();
verify(successCallback, times(1))
.accept("test", newPhoto);
@@ -269,7 +266,7 @@
mPhotoRestrictedByBase = true;
mController.createDialog(mActivity, mActivityStarter, mCurrentIcon,
- "test", "title", null, null);
+ "test", null, null);
assertThat(mController.mPhotoController).isNull();
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2c54d01..7d8b066 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -844,6 +844,8 @@
<uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR" />
<!-- Permission required for CTS test IntentRedirectionTest -->
<uses-permission android:name="android.permission.QUERY_CLONED_APPS" />
+ <!-- Permission required for accessing all content provider mime types -->
+ <uses-permission android:name="android.permission.GET_ANY_PROVIDER_TYPE" />
<application
android:label="@string/app_label"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7df3dfb..a443b5c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -250,17 +250,17 @@
"tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt",
"tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt",
// domain
- "tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt",
+ "tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt",
+ "tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt",
+ "tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt",
"tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt",
"tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt",
"tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt",
"tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt",
"tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt",
- "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt",
- "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt",
// ui
+ "tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt",
- "tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt",
"tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b7b86ef..2c0d73a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -370,7 +370,7 @@
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
tools:replace="android:appComponentFactory"
- android:appComponentFactory=".SystemUIAppComponentFactory">
+ android:appComponentFactory=".PhoneSystemUIAppComponentFactory">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
Setting the theme on the application does not affect views inflated by services.
The application theme is set again from onCreate to take effect for those views. -->
@@ -917,8 +917,9 @@
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:visibleToInstantApps="true">
- </activity>
+ android:visibleToInstantApps="true"
+ android:exported="true"
+ />
<activity android:name=".controls.management.ControlsEditingActivity"
android:label="@string/controls_menu_edit"
@@ -951,8 +952,9 @@
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|orientation"
- android:visibleToInstantApps="true">
- </activity>
+ android:visibleToInstantApps="true"
+ android:exported="true"
+ />
<activity android:name=".wallet.ui.WalletActivity"
android:label="@string/wallet_title"
@@ -1003,7 +1005,6 @@
android:name=".notetask.shortcut.LaunchNoteTaskActivity"
android:exported="true"
android:excludeFromRecents="true"
- android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay" >
<intent-filter>
@@ -1016,7 +1017,6 @@
android:name=".notetask.LaunchNotesRoleSettingsTrampolineActivity"
android:exported="true"
android:excludeFromRecents="true"
- android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay" >
<intent-filter>
<action android:name="com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE" />
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml
index fb31e1d..9d9b05a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/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">"Menü für Bedienungshilfen"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"Über das Menü „Bedienungshilfen“ lässt sich ein großes Menü zur Bedienung deines Geräts auf dem Bildschirm öffnen. Du kannst beispielsweise das Gerät sperren, die Lautstärke und Helligkeit anpassen und Screenshots machen."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Über das Menü für Bedienungshilfen lässt sich ein großes Menü zur Bedienung deines Geräts auf dem Bildschirm öffnen. Du kannst beispielsweise das Gerät sperren, die Lautstärke und Helligkeit anpassen und Screenshots machen."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistant"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Einstellungen für Bedienungshilfen"</string>
@@ -20,9 +20,9 @@
<string name="brightness_down_label" msgid="7115662941913272072">"Helligkeit verringern"</string>
<string name="previous_button_content_description" msgid="840869171117765966">"Zum vorherigen Bildschirm"</string>
<string name="next_button_content_description" msgid="6810058269847364406">"Zum nächsten Bildschirm"</string>
- <string name="accessibility_menu_description" msgid="4458354794093858297">"Über das Menü „Bedienungshilfen“ lässt sich ein großes Menü zur Bedienung deines Geräts auf dem Bildschirm öffnen. Du kannst beispielsweise das Gerät sperren, die Lautstärke und Helligkeit anpassen und Screenshots machen."</string>
+ <string name="accessibility_menu_description" msgid="4458354794093858297">"Über das Menü für Bedienungshilfen lässt sich ein großes Menü zur Bedienung deines Geräts auf dem Bildschirm öffnen. Du kannst beispielsweise das Gerät sperren, die Lautstärke und Helligkeit anpassen und Screenshots machen."</string>
<string name="accessibility_menu_summary" msgid="340071398148208130">"Gerät mit großem Menü steuern"</string>
- <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Menüeinstellungen f. Bedienungshilfen"</string>
+ <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Einstellungen für das Menü „Bedienungshilfen“"</string>
<string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Große Schaltflächen"</string>
<string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Schaltflächen für das Menü „Bedienungshilfen“ vergrößern"</string>
<string name="pref_help_title" msgid="6871558837025010641">"Hilfe"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml
index 9726f20..48c2634 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml
@@ -11,7 +11,7 @@
<string name="recent_apps_label" msgid="6583276995616385847">"Соңғы қолданбалар"</string>
<string name="lockscreen_label" msgid="648347953557887087">"Құлып экраны"</string>
<string name="quick_settings_label" msgid="2999117381487601865">"Жылдам параметрлер"</string>
- <string name="notifications_label" msgid="6829741046963013567">"Хабарланды00ADрулар"</string>
+ <string name="notifications_label" msgid="6829741046963013567">"Хабарландырулар"</string>
<string name="screenshot_label" msgid="863978141223970162">"Скриншот"</string>
<string name="screenshot_utterance" msgid="1430760563401895074">"Скриншот жасау"</string>
<string name="volume_up_label" msgid="8592766918780362870">"Дыбысын арттыру"</string>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 48dd08f..dbfa192 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -36,6 +36,7 @@
import com.android.app.animation.Interpolators
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CujType
+import com.android.systemui.animation.view.LaunchableFrameLayout
import com.android.systemui.util.registerAnimationOnBackInvoked
import kotlin.math.roundToInt
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index 7e1bfb9..addabcc 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -21,7 +21,6 @@
import android.util.Log
import android.util.LruCache
import android.util.MathUtils
-import android.util.MathUtils.abs
import androidx.annotation.VisibleForTesting
import java.lang.Float.max
import java.lang.Float.min
@@ -30,8 +29,6 @@
private const val TAG_ITAL = "ital"
private const val FONT_WEIGHT_DEFAULT_VALUE = 400f
-private const val FONT_WEIGHT_ANIMATION_FRAME_COUNT = 100
-
private const val FONT_ITALIC_MAX = 1f
private const val FONT_ITALIC_MIN = 0f
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
@@ -39,11 +36,12 @@
// Benchmarked via Perfetto, difference between 10 and 50 entries is about 0.3ms in
// frame draw time on a Pixel 6.
-@VisibleForTesting const val FONT_CACHE_MAX_ENTRIES = 10
+@VisibleForTesting const val DEFAULT_FONT_CACHE_MAX_ENTRIES = 10
/** Provide interpolation of two fonts by adjusting font variation settings. */
-class FontInterpolator {
-
+class FontInterpolator(
+ numberOfAnimationSteps: Int? = null,
+) {
/**
* Cache key for the interpolated font.
*
@@ -88,8 +86,9 @@
// Font interpolator has two level caches: one for input and one for font with different
// variation settings. No synchronization is needed since FontInterpolator is not designed to be
// thread-safe and can be used only on UI thread.
- private val interpCache = LruCache<InterpKey, Font>(FONT_CACHE_MAX_ENTRIES)
- private val verFontCache = LruCache<VarFontKey, Font>(FONT_CACHE_MAX_ENTRIES)
+ val cacheMaxEntries = numberOfAnimationSteps?.let { it * 2 } ?: DEFAULT_FONT_CACHE_MAX_ENTRIES
+ private val interpCache = LruCache<InterpKey, Font>(cacheMaxEntries)
+ private val verFontCache = LruCache<VarFontKey, Font>(cacheMaxEntries)
// Mutable keys for recycling.
private val tmpInterpKey = InterpKey(null, null, 0f)
@@ -128,18 +127,12 @@
val newAxes =
lerp(startAxes, endAxes) { tag, startValue, endValue ->
when (tag) {
- // TODO: Good to parse 'fvar' table for retrieving default value.
- TAG_WGHT -> {
- adaptiveAdjustWeight(
- MathUtils.lerp(
- startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- progress
- ),
+ TAG_WGHT ->
+ MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
+ progress
)
- }
TAG_ITAL ->
adjustItalic(
MathUtils.lerp(
@@ -175,9 +168,9 @@
val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
interpCache.put(InterpKey(start, end, progress), newFont)
verFontCache.put(VarFontKey(start, newAxes), newFont)
- if (DEBUG) {
- Log.d(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey")
- }
+
+ // Cache misses are likely to create memory leaks, so this is logged at error level.
+ Log.e(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey")
return newFont
}
@@ -225,15 +218,6 @@
return result
}
- // For the performance reasons, we animate weight with adaptive step. This helps
- // Cache hit ratio in the Skia glyph cache.
- // The reason we don't use fix step is because the range of weight axis is not normalized,
- // some are from 50 to 100, others are from 0 to 1000, so we cannot give a constant proper step
- private fun adaptiveAdjustWeight(value: Float, start: Float, end: Float): Float {
- val step = max(abs(end - start) / FONT_WEIGHT_ANIMATION_FRAME_COUNT, 1F)
- return coerceInWithStep(value, min(start, end), max(start, end), step)
- }
-
// For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustItalic(value: Float) =
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 16ddf0c..b555fa5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -108,7 +108,8 @@
}
// Following two members are for mutable for testing purposes.
- public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache)
+ public var textInterpolator: TextInterpolator =
+ TextInterpolator(layout, typefaceCache, numberOfAnimationSteps)
public var animator: ValueAnimator =
ValueAnimator.ofFloat(1f).apply {
duration = DEFAULT_ANIMATION_DURATION
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 8ed8d8f..02caeed 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -31,6 +31,7 @@
class TextInterpolator(
layout: Layout,
var typefaceCache: TypefaceVariantCache,
+ numberOfAnimationSteps: Int? = null,
) {
/**
* Returns base paint used for interpolation.
@@ -85,7 +86,7 @@
private class Line(val runs: List<Run>)
private var lines = listOf<Line>()
- private val fontInterpolator = FontInterpolator()
+ private val fontInterpolator = FontInterpolator(numberOfAnimationSteps)
// Recycling object for glyph drawing and tweaking.
private val tmpPaint = TextPaint()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt
similarity index 91%
rename from packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt
rename to packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt
index 2eb503b..7538f18 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.animation
+package com.android.systemui.animation.view
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
/** A [FrameLayout] that also implements [LaunchableView]. */
open class LaunchableFrameLayout : FrameLayout, LaunchableView {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 0e20444..8cba2ab 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -48,6 +48,18 @@
import kotlinx.coroutines.withContext
private val KEY_TIMESTAMP = "appliedTimestamp"
+private val KNOWN_PLUGINS =
+ mapOf<String, List<ClockMetadata>>(
+ "com.android.systemui.falcon.one" to listOf(ClockMetadata("ANALOG_CLOCK_BIGNUM")),
+ "com.android.systemui.falcon.two" to listOf(ClockMetadata("DIGITAL_CLOCK_CALLIGRAPHY")),
+ "com.android.systemui.falcon.three" to listOf(ClockMetadata("DIGITAL_CLOCK_FLEX")),
+ "com.android.systemui.falcon.four" to listOf(ClockMetadata("DIGITAL_CLOCK_GROWTH")),
+ "com.android.systemui.falcon.five" to listOf(ClockMetadata("DIGITAL_CLOCK_HANDWRITTEN")),
+ "com.android.systemui.falcon.six" to listOf(ClockMetadata("DIGITAL_CLOCK_INFLATE")),
+ "com.android.systemui.falcon.seven" to listOf(ClockMetadata("DIGITAL_CLOCK_METRO")),
+ "com.android.systemui.falcon.eight" to listOf(ClockMetadata("DIGITAL_CLOCK_NUMBEROVERLAP")),
+ "com.android.systemui.falcon.nine" to listOf(ClockMetadata("DIGITAL_CLOCK_WEATHER")),
+ )
private fun <TKey, TVal> ConcurrentHashMap<TKey, TVal>.concurrentGetOrPut(
key: TKey,
@@ -127,8 +139,61 @@
private val pluginListener =
object : PluginListener<ClockProviderPlugin> {
- override fun onPluginAttached(manager: PluginLifecycleManager<ClockProviderPlugin>) {
- manager.loadPlugin()
+ override fun onPluginAttached(
+ manager: PluginLifecycleManager<ClockProviderPlugin>
+ ): Boolean {
+ if (keepAllLoaded) {
+ // Always load new plugins if requested
+ return true
+ }
+
+ val knownClocks = KNOWN_PLUGINS.get(manager.getPackage())
+ if (knownClocks == null) {
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.WARNING,
+ { str1 = manager.getPackage() },
+ { "Loading unrecognized clock package: $str1" }
+ )
+ return true
+ }
+
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.INFO,
+ { str1 = manager.getPackage() },
+ { "Skipping initial load of known clock package package: $str1" }
+ )
+
+ var isClockListChanged = false
+ for (metadata in knownClocks) {
+ val id = metadata.clockId
+ val info =
+ availableClocks.concurrentGetOrPut(id, ClockInfo(metadata, null, manager)) {
+ isClockListChanged = true
+ onConnected(id)
+ }
+
+ if (manager != info.manager) {
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.ERROR,
+ { str1 = id },
+ { "Clock Id conflict on known attach: $str1 is double registered" }
+ )
+ continue
+ }
+
+ info.provider = null
+ }
+
+ if (isClockListChanged) {
+ triggerOnAvailableClocksChanged()
+ }
+ verifyLoadedProviders()
+
+ // Load executed via verifyLoadedProviders
+ return false
}
override fun onPluginLoaded(
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
index cd9fb88..e050604 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
@@ -148,11 +148,11 @@
*/
val isEnabled: Boolean = true,
/**
- * If the affordance is disabled, this is a set of instruction messages to be shown to the
- * user when the disabled affordance is selected. The instructions should help the user
- * figure out what to do in order to re-neable this affordance.
+ * If the affordance is disabled, this is the explanation to be shown to the user when the
+ * disabled affordance is selected. The instructions should help the user figure out what to
+ * do in order to re-neable this affordance.
*/
- val enablementInstructions: List<String>? = null,
+ val enablementExplanation: String? = null,
/**
* If the affordance is disabled, this is a label for a button shown together with the set
* of instruction messages when the disabled affordance is selected. The button should help
@@ -163,15 +163,14 @@
*/
val enablementActionText: String? = null,
/**
- * If the affordance is disabled, this is a "component name" of the format
- * `packageName/action` to be used as an `Intent` for `startActivity` when the action button
- * (shown together with the set of instruction messages when the disabled affordance is
- * selected) is clicked by the user. The button should help send the user to a flow that
- * would help them achieve the instructions and re-enable this affordance.
+ * If the affordance is disabled, this is an [Intent] to be used with `startActivity` when
+ * the action button (shown together with the set of instruction messages when the disabled
+ * affordance is selected) is clicked by the user. The button should help send the user to a
+ * flow that would help them achieve the instructions and re-enable this affordance.
*
* If `null`, the button should not be shown.
*/
- val enablementActionComponentName: String? = null,
+ val enablementActionIntent: Intent? = null,
/** Optional [Intent] to use to start an activity to configure this affordance. */
val configureIntent: Intent? = null,
)
@@ -327,20 +326,20 @@
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.IS_ENABLED
)
- val enablementInstructionsColumnIndex =
+ val enablementExplanationColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
- .ENABLEMENT_INSTRUCTIONS
+ .ENABLEMENT_EXPLANATION
)
val enablementActionTextColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_ACTION_TEXT
)
- val enablementComponentNameColumnIndex =
+ val enablementActionIntentColumnIndex =
cursor.getColumnIndex(
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
- .ENABLEMENT_COMPONENT_NAME
+ .ENABLEMENT_ACTION_INTENT
)
val configureIntentColumnIndex =
cursor.getColumnIndex(
@@ -352,9 +351,9 @@
nameColumnIndex == -1 ||
iconColumnIndex == -1 ||
isEnabledColumnIndex == -1 ||
- enablementInstructionsColumnIndex == -1 ||
+ enablementExplanationColumnIndex == -1 ||
enablementActionTextColumnIndex == -1 ||
- enablementComponentNameColumnIndex == -1 ||
+ enablementActionIntentColumnIndex == -1 ||
configureIntentColumnIndex == -1
) {
return@buildList
@@ -368,21 +367,22 @@
name = cursor.getString(nameColumnIndex),
iconResourceId = cursor.getInt(iconColumnIndex),
isEnabled = cursor.getInt(isEnabledColumnIndex) == 1,
- enablementInstructions =
- cursor
- .getString(enablementInstructionsColumnIndex)
- ?.split(
- Contract.LockScreenQuickAffordances.AffordanceTable
- .ENABLEMENT_INSTRUCTIONS_DELIMITER
- ),
+ enablementExplanation =
+ cursor.getString(enablementExplanationColumnIndex),
enablementActionText =
cursor.getString(enablementActionTextColumnIndex),
- enablementActionComponentName =
- cursor.getString(enablementComponentNameColumnIndex),
+ enablementActionIntent =
+ cursor
+ .getString(enablementActionIntentColumnIndex)
+ ?.toIntent(
+ affordanceId = affordanceId,
+ ),
configureIntent =
cursor
.getString(configureIntentColumnIndex)
- ?.toIntent(affordanceId = affordanceId),
+ ?.toIntent(
+ affordanceId = affordanceId,
+ ),
)
)
}
@@ -524,7 +524,7 @@
affordanceId: String,
): Intent? {
return try {
- Intent.parseUri(this, 0)
+ Intent.parseUri(this, Intent.URI_INTENT_SCHEME)
} catch (e: URISyntaxException) {
Log.w(TAG, "Cannot parse Uri into Intent for affordance with ID \"$affordanceId\"!")
null
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index f9e8aaf..b6d5ef3 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -81,8 +81,6 @@
const val TABLE_NAME = "affordances"
val URI: Uri =
LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI.buildUpon().appendPath(TABLE_NAME).build()
- const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
- const val COMPONENT_NAME_SEPARATOR = "/"
object Columns {
/** String. Unique ID for this affordance. */
@@ -97,22 +95,21 @@
/** Integer. `1` if the affordance is enabled or `0` if it disabled. */
const val IS_ENABLED = "is_enabled"
/**
- * String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be
- * shown to the user if the affordance is disabled and the user selects the
- * affordance.
+ * String. Text to be shown to the user if the affordance is disabled and the user
+ * selects the affordance.
*/
- const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
+ const val ENABLEMENT_EXPLANATION = "enablement_explanation"
/**
* String. Optional label for a button that, when clicked, opens a destination
* activity where the user can re-enable the disabled affordance.
*/
const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
/**
- * String. Optional package name and activity action string, delimited by
- * [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that
- * opens a destination where the user can re-enable the disabled affordance.
+ * String. Optional URI-formatted `Intent` (formatted using
+ * `Intent#toUri(Intent.URI_INTENT_SCHEME)` used to start an activity that opens a
+ * destination where the user can re-enable the disabled affordance.
*/
- const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
+ const val ENABLEMENT_ACTION_INTENT = "enablement_action_intent"
/**
* Byte array. Optional parcelled `Intent` to use to start an activity that can be
* used to configure the affordance.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 3ae328e..537b7a4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -190,7 +190,9 @@
data class ClockMetadata(
val clockId: ClockId,
val name: String,
-)
+) {
+ constructor(clockId: ClockId) : this(clockId, clockId) {}
+}
/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 34d31d9..4e39f1a 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/Android.bp
@@ -25,6 +25,9 @@
sdk_version: "current",
name: "PluginCoreLib",
srcs: ["src/**/*.java"],
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
// Enforce that the library is built against java 8 so that there are
// no compatibility issues with launcher
diff --git a/packages/SystemUI/plugin_core/proguard.flags b/packages/SystemUI/plugin_core/proguard.flags
new file mode 100644
index 0000000..6240898
--- /dev/null
+++ b/packages/SystemUI/plugin_core/proguard.flags
@@ -0,0 +1,11 @@
+# R8's full mode is a bit more aggressive in stripping annotations, but the
+# SystemUI plugin architecture requires these annotations at runtime. The
+# following rules are the minimal set necessary to ensure compatibility.
+# For more details, see:
+# https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode
+-keepattributes RuntimeVisible*Annotation*,AnnotationDefault
+
+-keep interface com.android.systemui.plugins.annotations.** {
+ *;
+}
+-keep,allowshrinking,allowoptimization,allowobfuscation,allowaccessmodification @com.android.systemui.plugins.annotations.** class *
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
index cc6a46f..56c3f93 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
@@ -16,12 +16,20 @@
package com.android.systemui.plugins;
+import android.content.ComponentName;
+
/**
* Provides the ability for consumers to control plugin lifecycle.
*
* @param <T> is the target plugin type
*/
public interface PluginLifecycleManager<T extends Plugin> {
+ /** Returns the ComponentName of the target plugin. Maybe be called when not loaded. */
+ ComponentName getComponentName();
+
+ /** Returns the package name of the target plugin. May be called when not loaded. */
+ String getPackage();
+
/** Returns the currently loaded plugin instance (if plugin is loaded) */
T getPlugin();
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
index c5f5032..bd0bd89 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginListener.java
@@ -60,13 +60,18 @@
/**
* Called when the plugin is first attached to the host application. {@link #onPluginLoaded}
- * will be automatically called as well when first attached. This may be called multiple times
- * if multiple plugins are allowed. It may also be called in the future if the plugin package
- * changes and needs to be reloaded. Each call to {@link #onPluginAttached} will provide a new
- * or different {@link PluginLifecycleManager}.
+ * will be automatically called as well when first attached if true is returned. This may be
+ * called multiple times if multiple plugins are allowed. It may also be called in the future
+ * if the plugin package changes and needs to be reloaded. Each call to
+ * {@link #onPluginAttached} will provide a new or different {@link PluginLifecycleManager}.
+ *
+ * @return returning true will immediately load the plugin and call onPluginLoaded with the
+ * created object. false will skip loading, but the listener can load it at any time using the
+ * provided PluginLifecycleManager. Loading plugins immediately is the default behavior.
*/
- default void onPluginAttached(PluginLifecycleManager<T> manager) {
+ default boolean onPluginAttached(PluginLifecycleManager<T> manager) {
// Optional
+ return true;
}
/**
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index a8ed843..b534fcec 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,13 +1,7 @@
-include proguard_common.flags
--keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.SystemUIInitializerImpl {
*;
}
--keep class com.android.systemui.tv.TvSystemUIInitializer {
- *;
-}
-
--keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; }
--keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.DaggerTvGlobalRootComponent** { !synthetic *; }
\ No newline at end of file
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; }
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 3fc0965..fc9c917 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -43,7 +43,7 @@
<!-- Not quite optimal but needed to translate these items as a group. The
NotificationIconContainer has its own logic for translation. -->
- <LinearLayout
+ <com.android.keyguard.KeyguardStatusAreaView
android:id="@+id/keyguard_status_area"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -63,5 +63,5 @@
android:paddingStart="@dimen/below_clock_padding_start_icons"
android:visibility="invisible"
/>
- </LinearLayout>
+ </com.android.keyguard.KeyguardStatusAreaView>
</com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index 3412a30..2fc1d2e 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -29,7 +29,7 @@
>
<include layout="@layout/keyguard_bouncer_message_area"/>
- <com.android.systemui.keyguard.bouncer.ui.BouncerMessageView
+ <com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 78a7c17..d9011c2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -33,7 +33,7 @@
android:clipToPadding="false">
<include layout="@layout/keyguard_bouncer_message_area"/>
- <com.android.systemui.keyguard.bouncer.ui.BouncerMessageView
+ <com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 01c5443..c7d2d81 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -29,7 +29,7 @@
androidprv:layout_maxWidth="@dimen/keyguard_security_width">
<include layout="@layout/keyguard_bouncer_message_area"/>
-<com.android.systemui.keyguard.bouncer.ui.BouncerMessageView
+<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/integers.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/integers.xml
index 2a80920..3d1cb5e 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/integers.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/integers.xml
@@ -16,5 +16,5 @@
-->
<resources>
<!-- Invisibility to use for the date & weather view when it is disabled by a clock -->
- <integer name="keyguard_date_weather_view_invisibility">8</integer>
+ <integer name="keyguard_date_weather_view_invisibility">4</integer>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index e8c7ef9..4df30dc 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -117,7 +117,7 @@
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ใช้รหัสผ่านแทนเพื่อเพิ่มความปลอดภัย"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ผู้ดูแลระบบล็อกอุปกรณ์"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"มีการล็อกอุปกรณ์ด้วยตัวเอง"</string>
- <string name="kg_face_not_recognized" msgid="7903950626744419160">"ไม่รู้จัก"</string>
+ <string name="kg_face_not_recognized" msgid="7903950626744419160">"ไม่รู้จักลายนิ้วมือ"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"เปิดการเข้าถึงกล้องในการตั้งค่าเพื่อใช้การปลดล็อกด้วยใบหน้า"</string>
<string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{ป้อน PIN ของซิม คุณพยายามได้อีก # ครั้งก่อนที่จะต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์}other{ป้อน PIN ของซิม คุณลองได้อีก # ครั้ง}}"</string>
<string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{ตอนนี้ซิมถูกปิดใช้แล้ว ป้อนรหัส PUK เพื่อดำเนินการต่อ คุณพยายามได้อีก # ครั้งก่อนที่ซิมจะใช้งานไม่ได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ}other{ตอนนี้ซิมถูกปิดใช้แล้ว ป้อนรหัส PUK เพื่อดำเนินการต่อ คุณพยายามได้อีก # ครั้งก่อนที่ซิมจะใช้งานไม่ได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ}}"</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 4b79689..39dd90e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -148,4 +148,9 @@
<dimen name="default_dot_diameter">34dp</dimen>
<dimen name="default_dot_spacing">0dp</dimen>
+ <!-- Weather clock smartspace scaling to apply for the weather clock -->
+ <item name="weather_clock_smartspace_scale" type="dimen" format="float">1.0</item>
+ <dimen name="weather_clock_smartspace_translateX">0dp</dimen>
+ <dimen name="weather_clock_smartspace_translateY">0dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/ids.xml b/packages/SystemUI/res-keyguard/values/ids.xml
index 0dff4ff..1435907 100644
--- a/packages/SystemUI/res-keyguard/values/ids.xml
+++ b/packages/SystemUI/res-keyguard/values/ids.xml
@@ -17,4 +17,18 @@
<resources>
<item type="id" name="header_footer_views_added_tag_key" />
+
+ <!-- animation channels for keyguard status area -->
+ <item type="id" name="translate_x_clock_design_animator_tag" />
+ <item type="id" name="translate_x_clock_design_animator_start_tag" />
+ <item type="id" name="translate_x_clock_design_animator_end_tag" />
+ <item type="id" name="translate_x_aod_animator_tag" />
+ <item type="id" name="translate_x_aod_animator_start_tag" />
+ <item type="id" name="translate_x_aod_animator_end_tag" />
+ <item type="id" name="translate_y_clock_size_animator_tag" />
+ <item type="id" name="translate_y_clock_size_animator_start_tag" />
+ <item type="id" name="translate_y_clock_size_animator_end_tag" />
+ <item type="id" name="translate_y_clock_design_animator_tag" />
+ <item type="id" name="translate_y_clock_design_animator_start_tag" />
+ <item type="id" name="translate_y_clock_design_animator_end_tag" />
</resources>
diff --git a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
index 07c428b..6194311 100644
--- a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
+++ b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
@@ -24,7 +24,7 @@
android:layout_gravity="end">
<!-- We add a background behind the UserAvatarView with the same color and with a circular shape
so that this view can be expanded into a Dialog or an Activity. -->
- <com.android.systemui.animation.LaunchableFrameLayout
+ <com.android.systemui.animation.view.LaunchableFrameLayout
android:id="@+id/kg_multi_user_avatar_with_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -42,5 +42,5 @@
systemui:framePadding="0dp"
systemui:frameWidth="0dp">
</com.android.systemui.statusbar.phone.UserAvatarView>
- </com.android.systemui.animation.LaunchableFrameLayout>
+ </com.android.systemui.animation.view.LaunchableFrameLayout>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
index a595566..7105721 100644
--- a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
@@ -110,7 +110,9 @@
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="end"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:ellipsize="marquee"
+ android:singleLine="true"
android:maxLines="1"
android:textColor="@color/media_dialog_item_main_content"
android:textSize="14sp"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index cd22df4..70d0983 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesig is gestaaf"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestig"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestig om te voltooi"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Ontsluit met gesig."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontsluit met gesig. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesig is herken. Druk om voort te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesig is herken. Druk die ontsluitikoon om voort te gaan."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Oudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kopstuk"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Gehoortoestelle"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Skakel tans aan …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outo-draai"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan nie stoor nie. Probeer weer."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan nie stoor nie."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gebruik minstens 4 karakters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Gebruik minder as 16 karakters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
<string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistent luister"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Maak notas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Maak notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitsaai"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"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="7889684551194225793">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index dfba943..316d762 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"መልክ ተረጋግጧል"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ተረጋግጧል"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ለማጠናቀቅ አረጋግጥን መታ ያድርጉ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"በመልክ ተከፍቷል።"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"በመልክ ተከፍቷል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"መልክ ተለይቶ ታውቋል። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"መልክ ተለይቶ ታውቋል። ለመቀጠል የመክፈቻ አዶውን ይጫኑ።"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"አጋዥ መስሚያዎች"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ማስቀመጥ አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ማስቀመጥ አልተቻለም።"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ቢያንስ 4 ቁምፊዎችን ይጠቀሙ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"ከ16 የሚያንሱ ቁምፊዎችን ይጠቀሙ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"ረዳት በማዳመጥ ላይ ነው"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>፣ <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"የማስታወሻ አያያዝ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"የማስታወሻ አያያዝ፣ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"በማሰራጨት ላይ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ማሰራጨት ይቁም?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>ን ካሰራጩ ወይም ውፅዓትን ከቀየሩ የአሁኑ ስርጭትዎ ይቆማል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a19386b..6ae9ff4 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"تمّت مصادقة الوجه."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"تم فتح قفل جهازك عند تقريبه من وجهك."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط للمتابعة."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"تم التعرّف على الوجه. اضغط للمتابعة."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"تم التعرّف على الوجه. للمتابعة، اضغط على رمز فتح القفل."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"سماعات الأذن الطبية"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"لا يمكن إجراء الحفظ. يُرجى إعادة المحاولة."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"لا يمكن إجراء الحفظ."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"يجب استخدام 4 أحرف على الأقل."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"يجب أن يحتوي الرمز على أقل من 16 حرفًا."</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"يستمع \"مساعد Google\" إليك الآن."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"تدوين الملاحظات"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"تدوين الملاحظات في \"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>\""</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"البث"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 5d4e896..528be9f 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"নিশ্চিত কৰিলে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূৰ্ণ কৰিবলৈ নিশ্চিত কৰক-ত টিপক"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা।"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"মুখাৱয়বৰ জৰিয়তে আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ টিপক।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"মুখাৱয়ব চিনাক্ত কৰা হৈছে। অব্যাহত ৰাখিবলৈ আনলক কৰক চিহ্নটোত টিপক।"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"শ্ৰৱণ যন্ত্ৰ"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ছেভ কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ছেভ কৰিব নোৱাৰি।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"অতি কমেও ৪ টা বৰ্ণ ব্যৱহাৰ কৰক"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"১৬ টাতকৈ কম বৰ্ণ ব্যৱহাৰ কৰক"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistantএ শুনি আছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"টোকা গ্ৰহণ কৰা"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"টোকা গ্ৰহণ কৰা, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"সম্প্ৰচাৰণ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 0107268..72d2560 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Üz doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Təsdiqləndi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamaq üçün \"Təsdiq edin\" seçiminə toxunun"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Üz ilə kiliddən çıxarılıb."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Üz ilə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Üz tanınıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Üz tanınıb. \"Kiliddən çıxar\" ikonasına basıb davam edin."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Qulaqlıq"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Eşitmə cihazları"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Yadda saxlamaq mümkün deyil. Yenə cəhd edin."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Yadda saxlamaq mümkün deyil."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Ən azı 4 simvoldan istifadə edin"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Maksimum 16 simvoldan istifadə edin"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistent dinləyir"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Qeydgötürmə"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Qeydgötürmə, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayım"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 173a8fb..0d0b5fa 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je potvrđeno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da biste završili"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Otključano je licem."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano je licem. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu otključavanja za nastavak."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Slušni aparati"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključuje se..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Čuvanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Čuvanje nije uspelo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Koristite bar 4 znaka"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Koristite manje od 16 znakova"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Pomoćnik sluša"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obaveštenje}one{# obaveštenje}few{# obaveštenja}other{# obaveštenja}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pravljenje beležaka"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pravljenje beležaka, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitovanje"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite da zaustavite emitovanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitujete aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promenite izlaz, aktuelno emitovanje će se zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 918372e..ba8c998 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -142,7 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Твар распазнаны"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Пацверджана"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Націсніце \"Пацвердзіць\", каб завяршыць"</string>
- <!-- no translation found for biometric_dialog_tap_confirm_with_face (3783056044917913453) -->
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
<skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблакіравана распазнаваннем твару. Націсніце для працягу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Твар распазнаны. Націсніце для працягу."</string>
@@ -244,7 +244,8 @@
<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="3003338571871392293">"Слыхавыя апараты"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1005,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не ўдалося захаваць. Паўтарыце спробу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не ўдалося захаваць."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Скарыстайце не менш як 4 сімвалы"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Скарыстайце менш за 16 сімвалаў"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 841dc6e..69f08ec 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е удостоверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потвърдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Докоснете „Потвърждаване“ за завършване"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Отключено с лице."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отключено с лице. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето бе разпознато. Натиснете, за да продължите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето бе разпознато. Продължете чрез иконата за отключване."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Слухови апарати"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се запази. Опитайте отново."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се запази."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Използвайте поне 4 знака"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Използвайте по-малко от 16 знака"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Асистент слуша"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Водене на бележки"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Водене на бележки, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Излъчване"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f2404fa..f2eb8ca 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ফেস যাচাই করা হয়েছে"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"কনফার্ম করা হয়েছে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূর্ণ করতে \'কনফার্ম করুন\' বোতামে ট্যাপ করুন"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ফেসের সাহায্যে আনলক করা হয়েছে।"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ফেসের সাহায্যে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ফেস শনাক্ত করা হয়েছে। চালিয়ে যেতে আনলক আইকন প্রেস করুন।"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"হিয়ারিং এড"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"সেভ করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"সেভ করা যাচ্ছে না।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"কমপক্ষে ৪টি অক্ষর ব্যবহার করুন"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"১৬টির চেয়ে কম অক্ষর ব্যবহার করুন"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant শুনছে"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"নোট নেওয়া"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"নোট নেওয়া, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ব্রডকাস্ট করা হচ্ছে"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"আপনি <xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করলে বা আউটপুট পরিবর্তন করলে, আপনার বর্তমান সম্প্রচার বন্ধ হয়ে যাবে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 0f4f035..25a212d 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je provjereno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da završite"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Otključano je licem."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano licem. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice prepoznato. Pritisnite da nastavite."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice prepoznato. Pritisnite ikonu za otklj. da nastavite."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ulaz"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Slušni aparat"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nije moguće sačuvati. Pokušajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nije moguće sačuvati."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Koristite najmanje 4 znaka"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Koristite manje od 16 znakova"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistent sluša"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pisanje bilješki"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pisanje bilješki, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a02363e..9758360 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirma per completar"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"S\'ha desbloquejat amb la cara."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"S\'ha reconegut la cara. Prem per continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"S\'ha reconegut la cara. Prem la icona per continuar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Audiòfons"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"S\'està activant…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No es pot desar. Torna-ho a provar."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No es pot desar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilitza 4 caràcters com a mínim"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Utilitza menys de 16 caràcters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"L\'assistent t\'escolta"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}many{# notificacions}other{# notificacions}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Presa de notes"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Presa de notes, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"S\'està emetent"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c2b7c54..ba275ea 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Obličej byl ověřen"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrzeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ověření dokončíte klepnutím na Potvrdit"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Odemknuto obličejem."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odemknuto obličejem. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obličej rozpoznán. Pokračujte stisknutím."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obličej rozpoznán. Klepněte na ikonu odemknutí."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Sluchátka"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Naslouchátka"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Uložení se nezdařilo. Zkuste to znovu."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Uložení se nezdařilo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Heslo musí mít alespoň 4 znaky"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Použijte méně než 16 znaků"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistent poslouchá"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g> <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Psaní poznámek"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Psaní poznámek, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysílání"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"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="7889684551194225793">"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>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 53c15e1..4a1654a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansigtet er godkendt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekræftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tryk på Bekræft for at udføre"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Låst op ved hjælp af ansigt."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst op ved hjælp af ansigt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansigt genkendt. Tryk for at fortsætte."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansigt genkendt. Tryk på oplåsningsikonet for at fortsætte."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Høreapparater"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverer…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Der kan ikke gemmes. Prøv igen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Der kan ikke gemmes."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Angiv mindst 4 tegn"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Angiv højst 16 tegn"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Google Assistent lytter med"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikation}one{# notifikation}other{# notifikationer}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Notetagning"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notetagning, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Udsender"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 13a6fab..2cfcb4f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesicht authentifiziert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bestätigt"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Zum Abschließen auf \"Bestätigen\" tippen"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Gerät per Gesichtserkennung entsperrt."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Gerät mit dem Gesicht entsperrt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gesicht erkannt. Tippe, um fortzufahren."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gesicht erkannt. Tippe zum Fortfahren auf das Symbol „Entsperren“."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Eingabe"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hörgeräte"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Wird aktiviert…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
@@ -467,7 +469,7 @@
<string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Deine privaten Apps sind über <xliff:g id="VPN_APP">%1$s</xliff:g> mit dem Internet verbunden. Deine Netzwerkaktivitäten, einschließlich E-Mails und Browserdaten, sind für deinen VPN-Anbieter sichtbar."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN-Einstellungen öffnen"</string>
- <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dieses Gerät wird von deinen Eltern verwaltet. Sie können unter anderem Informationen über deine genutzten Apps, deinen Standort und deine Gerätenutzungsdauer einsehen und verwalten."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dieses Gerät wird von deinen Eltern verwaltet. Sie können unter anderem Informationen über deine genutzten Apps, deinen Standort und deine Bildschirmzeit einsehen und verwalten."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Durch TrustAgent entsperrt"</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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Speichern nicht möglich. Versuche es noch einmal."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Speichern nicht möglich."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gib mindestens vier Zeichen ein"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Maximal 16 Zeichen möglich"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
<string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 32f3ff6..56e8fb7 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Επιβεβαιώθηκε"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Πατήστε Επιβεβαίωση για ολοκλήρωση"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Ξεκλειδώθηκε με αναγνώριση προσώπου."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ξεκλείδωμα με αναγνώριση προσώπου. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Το πρόσωπο αναγνωρίστηκε. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Το πρόσωπο αναγνωρ. Πατήστε το εικον. ξεκλειδ. για συνέχεια."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Βοηθήματα ακρόασης"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Δεν είναι δυνατή η αποθήκευση. Δοκιμάστε ξανά."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Δεν είναι δυνατή η αποθήκευση."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Χρησιμοποιήστε τουλάχιστον 4 χαρακτήρες"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Χρησιμοποιήστε λιγότερους από 16 χαρακτήρες"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Ο Βοηθός ακούει"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ειδοποίηση}other{# ειδοποιήσεις}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Δημιουργία σημειώσεων"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Δημιουργία σημειώσεων, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Μετάδοση"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Διακοπή μετάδοσης με την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Εάν κάνετε μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g> ή αλλάξετε την έξοδο, η τρέχουσα μετάδοση θα σταματήσει"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d613f4c..3cdfccb 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hearing aids"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
@@ -988,7 +989,7 @@
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
- <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
+ <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use fewer than 16 characters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant is listening"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3af0ca9..23d399e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -142,7 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Unlocked by face"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognized. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognized. Press the unlock icon to continue."</string>
@@ -243,7 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hearing Aids"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
@@ -1004,7 +1004,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least 4 characters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use fewer than 16 characters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d613f4c..3cdfccb 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hearing aids"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
@@ -988,7 +989,7 @@
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
- <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
+ <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use fewer than 16 characters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant is listening"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d613f4c..3cdfccb 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognised. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognised. Press the unlock icon to continue."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hearing aids"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
@@ -988,7 +989,7 @@
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Available devices for audio output."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
- <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & displays"</string>
+ <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least four characters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use fewer than 16 characters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant is listening"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 457a8c2..112d0bd 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -142,7 +142,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Unlocked by face."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Unlocked by face"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Unlocked by face. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Face recognized. Press to continue."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Face recognized. Press the unlock icon to continue."</string>
@@ -243,7 +243,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hearing Aids"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
@@ -1004,7 +1004,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Can’t save. Try again."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Can’t save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use at least 4 characters"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use fewer than 16 characters"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 226bd0d..bd75476 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Se autenticó el rostro"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Se desbloqueó con rostro."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueo con rostro. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rostro reconocido. Presiona para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rostro reconocido. Presiona el desbloqueo para continuar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Audífonos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Vuelve a intentarlo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa al menos 4 caracteres"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Usa menos de 16 caracteres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistente está escuchando"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Tomar notas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Tomar notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index d16c789..37d1d18 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar la acción"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Desbloqueado con la cara."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado con la cara. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Cara reconocida. Pulsa para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Cara reconocida. Pulsa el icono de desbloquear para continuar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Audífonos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
@@ -989,7 +991,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altavoces y pantallas"</string>
- <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Sugerencias de dispositivos"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Detén tu sesión compartida para transferir el contenido multimedia a otro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Detener"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"No se puede guardar. Inténtalo de nuevo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"No se puede guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa 4 caracteres como mínimo"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Usa menos de 16 caracteres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"El Asistente está escuchando"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Toma de notas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Toma de notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index cf3fa34..5936e42 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Nägu on autenditud"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kinnitatud"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lõpuleviimiseks puudutage nuppu Kinnita"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Avati näoga."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avati näoga. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nägu tuvastati. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nägu tuvastati. Jätkamiseks vajutage avamise ikooni."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Heli"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Peakomplekt"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sisend"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Kuuldeaparaadid"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ei saa salvestada. Proovige uuesti."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ei saa salvestada."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Kasutage vähemalt 4 tähemärki"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Kasutage vähem kui 16 tähemärki"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
<string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistent kuulab"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Märkmete tegemine"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Märkmete tegemine <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Edastamine"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 2e9254b..26cebd5 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autentifikatu da aurpegia"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Berretsita"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Amaitzeko, sakatu \"Berretsi\""</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Aurpegiaren bidez desblokeatu da."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ezagutu da aurpegia. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ezagutu da aurpegia. Aurrera egiteko, sakatu desblokeatzeko ikonoa."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Entzungailua"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sarrera"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Audifonoak"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktibatzen…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ezin da gorde. Saiatu berriro."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ezin da gorde."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Erabili lau karaktere gutxienez"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Erabili 16 karaktere baino gutxiago"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
<string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Laguntzailea entzuten ari da"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Oharrak idaztea"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Oharrak idaztea, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Igortzen"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d550c6d..09a802f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چهره اصالتسنجی شد"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تأیید شد"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"برای تکمیل، روی تأیید ضربه بزنید"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"قفل با چهره باز شد."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"قفلْ با چهره باز شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چهره شناسایی شد. برای ادامه، فشار دهید."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چهره شناسایی شد. برای ادامه، نماد قفلگشایی را فشار دهید."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"سمعک"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ذخیره نشد. دوباره امتحان کنید."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ذخیره نشد."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"حداقل از ۴ نویسه استفاده کنید"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"از کمتر از ۱۶ نویسه استفاده کنید"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"«دستیار» درحال گوش کردن است"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"یادداشتبرداری"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"یادداشتبرداری، <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"همهفرستی"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"همهفرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همهفرستی کنید یا خروجی را تغییر دهید، همهفرستی کنونی متوقف خواهد شد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 88aa8b2..dcc193b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Kasvot tunnistettu"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Vahvistettu"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Valitse lopuksi Vahvista"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Avattu kasvojen avulla."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Avattu kasvojen avulla. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Kasvot tunnistettu. Jatka painamalla."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Kasvot tunnistettu. Jatka lukituksen avauskuvakkeella."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ääni"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Syöttölaite"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Kuulolaitteet"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Otetaan käyttöön…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tallennus ei onnistu. Yritä uudelleen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tallennus ei onnistu."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Käytä vähintään 4 merkkiä"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Käytä alle 16 merkkiä"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
<string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant kuuntelee"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Muistiinpanojen tekeminen"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Muistiinpanot, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Lähettää"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 4e85a84..d53a390 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Touchez Confirmer pour terminer"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Déverrouillé avec le visage."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverr. par reconnaissance faciale. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur Déverrouiller pour continuer."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Écouteurs"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Prothèses auditives"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilisez au moins 4 caractères"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Utilisez moins de 16 caractères"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"L\'Assistant est à l\'écoute"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# de notifications}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Prise de note"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Prise de note, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 9295b54..935a465 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Appuyez sur \"Confirmer\" pour terminer"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Déverrouillé par le visage."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Déverrouillé par visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Visage reconnu. Appuyez pour continuer."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Visage reconnu. Appuyez sur l\'icône de déverrouillage pour continuer."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Casque"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Appareils auditifs"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossible d\'enregistrer. Réessayez."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossible d\'enregistrer."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utilisez au moins quatre caractères"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Utilisez moins de 16 caractères"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"L\'Assistant écoute"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# notifications}other{# notifications}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Prise de notes"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Prise de notes, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index c4a883e..307e347 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autenticouse a cara"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar o proceso"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Usouse o desbloqueo facial."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Usouse o desbloqueo facial. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Recoñeceuse a cara. Preme para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Recoñeceuse a cara. Preme a icona de desbloquear."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Audiófonos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Non se puido gardar a información. Téntao de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Non se pode gardar a información."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Utiliza como mínimo 4 caracteres"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Utiliza menos de 16 caracteres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"O Asistente está escoitando"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Toma de notas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Toma de notas (<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>)"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Difusión"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d3b20b30..4b5d6e5 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ચહેરાનું પ્રમાણીકરણ થયું"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"પુષ્ટિ કરી"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"પરીક્ષણ પૂર્ણ કરવા કન્ફર્મ કરોને ટૅપ કરો"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ચહેરા દ્વારા અનલૉક કર્યું."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ચહેરા દ્વારા અનલૉક કર્યું. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ચહેરો ઓળખ્યો. આગળ વધવા માટે દબાવો."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ચહેરો ઓળખ્યો. આગળ વધવા \'અનલૉક કરો\' આઇકન દબાવો."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"શ્રવણ યંત્રો"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"સાચવી શકતા નથી. ફરી પ્રયાસ કરો."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"સાચવી શકતા નથી."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ઓછામાં ઓછા 4 અક્ષરનો ઉપયોગ કરો"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 કરતાં ઓછા અક્ષરનો ઉપયોગ કરો"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant સાંભળી રહ્યું છે"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# નોટિફિકેશન}one{# નોટિફિકેશન}other{# નોટિફિકેશન}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"નોંધ લેવી"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"નોંધ લેવી, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"બ્રૉડકાસ્ટ કરી રહ્યાં છે"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> બ્રોડકાસ્ટ કરવાનું રોકીએ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"જો તમે <xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો અથવા આઉટપુટ બદલો, તો તમારું હાલનું બ્રોડકાસ્ટ બંધ થઈ જશે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 354ada8..8e95012 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरे की पुष्टि हो गई"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि हो गई"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"\'पुष्टि करें\' पर टैप करके पूरा करें"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"चेहरे से अनलॉक किया गया."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहरे से अनलॉक किया गया. जारी रखने के लिए टैप करें."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरे की पहचान हो गई. जारी रखने के लिए टैप करें."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरे की पहचान हो गई. जारी रखने के लिए अनलॉक आइकॉन को टैप करें."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"कान की मशीन"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -984,7 +986,7 @@
<string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"किसी डिवाइस को कनेक्ट करें"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
- <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करना बंद करें"</string>
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडियो आउटपुट के लिए उपलब्ध डिवाइस."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"वॉल्यूम"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव नहीं किया जा सका. फिर से कोशिश करें."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव नहीं किया जा सका."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"कम से कम चार वर्ण इस्तेमाल करें"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 वर्ण से कम इस्तेमाल करें"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant सुन रही है"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"नोट बनाएं"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोट लेने के लिए, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट ऐप्लिकेशन"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index a66e21b..e9fedc4 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je autentificirano"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi za dovršetak"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Otključano licem."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Otključano pomoću lica. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Lice je prepoznato. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Lice je prepoznato. Pritisnite ikonu otključavanja da biste nastavili."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Slušni aparati"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. zakretanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Spremanje nije uspjelo. Pokušajte ponovo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Spremanje nije uspjelo."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Upotrijebite barem četiri znaka"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Upotrijebite manje od 16 znakova"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistent sluša"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pisanje bilježaka"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pisanje bilježaka, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, vaše će se trenutačno emitiranje zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7284bb3..002d8d7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Arc hitelesítve"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Megerősítve"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Koppintson a Megerősítés lehetőségre"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Zárolás arccal feloldva."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Zárolás arccal feloldva. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Arc felismerve. Koppintson a folytatáshoz."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Arc felismerve. A folytatáshoz koppintson a Feloldásra."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hang"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Bevitel"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hallókészülékek"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Bekapcsolás…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"A mentés nem sikerült. Próbálja újra."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"A mentés nem sikerült."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Legalább négy karaktert használjon"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Legfeljebb 16 karaktert használhat"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
<string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"A Segéd figyel"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Jegyzetelés"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Jegyzetelés, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sugárzás"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index c419a3c..f82e930 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Դեմքը ճանաչվեց"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Հաստատվեց"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ավարտելու համար հպեք «Հաստատել»"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Ապակողպվել է դեմքով։"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ապակողպվել է դեմքով։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Դեմքը ճանաչվեց։ Սեղմեք շարունակելու համար։"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Դեմքը ճանաչվեց։ Սեղմեք ապակողպման պատկերակը։"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Լսողական ապարատ"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Չհաջողվեց պահել։ Նորից փորձեք։"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Չհաջողվեց պահել։"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Օգտագործեք առնվազն 4 նիշ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Օգտագործեք ոչ ավել քան 16 նիշ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Օգնականը լսում է"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Նշումների ստեղծում"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Նշումների ստեղծում, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Հեռարձակում"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 44a9a2a..cf3a21e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah diautentikasi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Dikonfirmasi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketuk Konfirmasi untuk menyelesaikan"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Kunci dibuka dengan wajah."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Kunci dibuka dengan wajah. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dikenali. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dikenali. Tekan ikon buka kunci untuk melanjutkan."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Alat Bantu Dengar"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Mengaktifkan…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat menyimpan. Coba lagi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat menyimpan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gunakan minimal 4 karakter"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Gunakan kurang dari 16 karakter"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
<string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant sedang mendengarkan"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pembuatan catatan"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pembuatan catatan, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index fbcbbe1..03a52c8 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Andlit staðfest"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Staðfest"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ýttu á „Staðfesta“ til að ljúka"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Opnað með andliti."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Opnað með andliti. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Andlitið var greint. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Andlitið var greint. Ýttu á opnunartáknið til að halda áfr."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hljóð"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Höfuðtól"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Inntak"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Heyrnartæki"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Kveikir…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ekki hægt að vista. Reyndu aftur."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ekki hægt að vista."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Notaðu að minnsta kosti 4 stafi"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Notaðu færri en 16 stafi"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
<string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Hjálparinn er að hlusta"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Glósugerð"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Glósugerð, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Útsending í gangi"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8fe8326..0bab880 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Volto autenticato"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confermato"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tocca Conferma per completare"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Sbloccato con il volto."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Sbloccato con il volto. Premi per continuare."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Volto riconosciuto. Premi per continuare."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Volto riconosciuto. Premi l\'icona Sblocca e continua."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auricolare"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingresso"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Apparecchi acustici"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Attivazione…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
@@ -913,7 +915,7 @@
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Mostra altre app"</string>
<string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Riordina"</string>
<string name="controls_favorite_add_controls" msgid="1221420435546694004">"Aggiungi controlli"</string>
- <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Torna alle modifiche"</string>
+ <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Torna alla modifica"</string>
<string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossibile caricare i controlli. Verifica nell\'app <xliff:g id="APP">%s</xliff:g> che le relative impostazioni non siano cambiate."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"Controlli compatibili non disponibili"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Impossibile salvare. Riprova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Impossibile salvare."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Usa almeno 4 caratteri"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Usa meno di 16 caratteri"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
<string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"L\'assistente è in ascolto"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}many{# notifiche}other{# notifiche}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Aggiunta di note"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Aggiunta di note, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index fb87249..45113e4 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"זיהוי הפנים בוצע"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"הנעילה בוטלה באמצעות זיהוי הפנים."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"הנעילה בוטלה באמצעות זיהוי הפנים. יש ללחוץ כדי להמשיך."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"הפנים זוהו. יש ללחוץ כדי להמשיך."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"הפנים זוהו. להמשך יש ללחוץ על סמל ביטול הנעילה."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"מכשירי שמיעה"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"לא ניתן לשמור. כדאי לנסות שוב."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"לא ניתן לשמור."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"יש להזין 4 תווים לפחות"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"אפשר להזין עד 16 תווים"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"מספר ה-Build הועתק ללוח."</string>
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant מאזינה"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}one{# התראות}two{# התראות}other{# התראות}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"כתיבת הערות"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"כתיבת הערות, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"שידור"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index bd12f1e..e39c979 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"顔を認証しました"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認しました"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"完了するには [確認] をタップしてください"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"顔でロック解除しました。"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"顔でロック解除しました。押して続行してください。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"顔を認識しました。押して続行してください。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"顔を認識しました。ロック解除アイコンを押して続行します。"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"補聴器"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ON にしています…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"保存できません。もう一度お試しください。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"保存できません。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"4 文字以上にしてください"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"使用できる文字数は 16 文字未満です"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index a2f1fb6..de5a393 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"სახის ამოცნობილია"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"დადასტურებული"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"დასასრულებლად შეეხეთ „დადასტურებას“"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"განიბლოკა სახით."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"განიბლოკა სახით. დააჭირეთ გასაგრძელებლად."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ამოცნობილია სახით. დააჭირეთ გასაგრძელებლად."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ამოცნობილია სახით. გასაგრძელებლად დააჭირეთ განბლოკვის ხატულას."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"სმენის მოწყობილობები"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"შენახვა ვერ ხერხდება. ცადეთ ხელახლა."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"შენახვა ვერ ხერხდება."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"გამოიყენეთ მინიმუმ 4 სიმბოლო."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"გამოიყენეთ 16-ზე ნაკლები სიმბოლო"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 709ac78..5187026 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Бет танылды."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Расталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Аяқтау үшін \"Растау\" түймесін түртіңіз."</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Бетпен ашылды."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Бетпен ашылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Бет танылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Бет танылды. Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Aудио"</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="3003338571871392293">"Есту аппараттары"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сақталмайды. Қайталап көріңіз."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сақталмайды."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Кемінде 4 таңба пайдаланыңыз."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Ең көбі 16 таңба пайдаланыңыз."</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant тыңдап тұр."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Ескертпе жазу"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ескертпе жазу, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Таратуда"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 9fb141b..ea6ae29 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"បានផ្ទៀងផ្ទាត់មុខ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"បានបញ្ជាក់"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ចុច \"បញ្ជាក់\" ដើម្បីបញ្ចប់"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"បានដោះសោដោយប្រើមុខ។"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"បានដោះសោដោយប្រើមុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"បានស្គាល់មុខ។ សូមចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"បានស្គាល់មុខ។ សូមចុចរូបដោះសោ ដើម្បីបន្ត។"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"មិនអាចរក្សាទុកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"មិនអាចរក្សាទុកបានទេ។"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ប្រើយ៉ាងហោចណាស់ 4 តួអក្សរ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"ប្រើតិចជាង 16 តួអក្សរ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Google Assistant កំពុងស្តាប់"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការជូនដំណឹង #}other{ការជូនដំណឹង #}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"ការកត់ត្រា"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ការកត់ត្រា, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ការផ្សាយ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ប្រសិនបើអ្នកផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹងបញ្ឈប់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 74917399..4155ead 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ಪೂರ್ಣಗೊಳಿಸಲು ದೃಢೀಕರಿಸಿ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ಮುಖವನ್ನು ಬಳಸಿ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ಮುಖ ಗುರುತಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಅನ್ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿ."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ಕನಿಷ್ಠ 4 ಅಕ್ಷರಗಳನ್ನು ಬಳಸಿ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 ಕ್ಕಿಂತ ಕಡಿಮೆ ಅಕ್ಷರಗಳನ್ನು ಬಳಸಿ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"ಅಸಿಸ್ಟೆಂಟ್ ಆಲಿಸುತ್ತಿದೆ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ನೋಟಿಫಿಕೇಶನ್}one{# ನೋಟಿಫಿಕೇಶನ್ಗಳು}other{# ನೋಟಿಫಿಕೇಶನ್ಗಳು}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"ಟಿಪ್ಪಣಿ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ಟಿಪ್ಪಣಿ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ಪ್ರಸಾರ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಬೇಕೆ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ನೀವು <xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿದರೆ ಅಥವಾ ಔಟ್ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿದರೆ, ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪ್ರಸಾರವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e2fc448..e5092b4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"얼굴이 인증되었습니다."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"확인함"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"완료하려면 확인을 탭하세요."</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"얼굴 인식으로 잠금 해제되었습니다."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"얼굴 인식으로 잠금 해제되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"얼굴이 인식되었습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"얼굴이 인식되었습니다. 계속하려면 아이콘을 누르세요."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"보청기"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"저장할 수 없습니다. 다시 시도해 주세요."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"저장할 수 없습니다."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"4자 이상 입력하세요."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16자 미만이어야 합니다."</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"어시스턴트가 대기 중입니다."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"메모"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"메모, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"방송 중"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ef84cb5..12a7439b 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Жүздүн аныктыгы текшерилди"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ырасталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Бүтүрүү үчүн \"Ырастоо\" баскычын басыңыз"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Түзмөгүңүздү жүзүңүз менен ачтыңыз."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Кулпуну жүзүңүз менен ачтыңыз. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Жүз таанылды. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Жүз таанылды. Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Угуу аппараттары"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Сакталган жок. Кайталап көрүңүз."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Сакталган жок."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Кеминде 4 символдон турушу керек"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 символдон ашпашы керек"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Жардамчы угуп жатат"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Эскертме жазуу"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Эскертме жазуу (<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>)"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Кеңири таратуу"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3ca429f..7e81735 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ຢືນຢັນແລ້ວ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ແຕະຢືນຢັນເພື່ອສຳເລັດ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ປົດລັອກດ້ວຍໃບໜ້າແລ້ວ."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ປົດລັອກດ້ວຍໜ້າແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ຈຳແນກໜ້າໄດ້ແລ້ວ. ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ເຄື່ອງຊ່ວຍຟັງ"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ບໍ່ສາມາດບັນທຶກໄດ້. ກະລຸນາລອງໃໝ່."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ບໍ່ສາມາດບັນທຶກໄດ້."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ໃຊ້ຢ່າງໜ້ອຍ 4 ຕົວອັກສອນ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"ໃຊ້ໜ້ອຍກວ່າ 16 ຕົວອັກສອນ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"ຜູ້ຊ່ວຍກຳລັງຟັງ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"ການຈົດບັນທຶກ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ການຈົດບັນທຶກ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ກຳລັງອອກອາກາດ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 84b405b..87ba40f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Veidas autentifikuotas"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Patvirtinta"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Paliesk. „Patvirtinti“, kad užbaigtumėte"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Atrakinta pagal veidą."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Veidas atpažintas. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Veidas atpažintas. Tęskite paspaudę atrakinimo piktogramą."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Virtualiosios realybės įrenginys"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Įvestis"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Klausos aparatai"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Įjungiama…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nepavyko išsaugoti. Bandykite dar kartą."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nepavyko išsaugoti."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Naudokite bent 4 simbolius"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Naudokite daugiausia 16 simbolių"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
<string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Padėjėjas klausosi"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Užrašų kūrimas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Užrašų kūrimas, „<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>“"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transliavimas"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2b9ecc5..e9f34074 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Seja autentificēta"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Apstiprināts"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lai pabeigtu, pieskarieties Apstiprināt"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Ierīce atbloķēta pēc sejas."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ierīce atbloķēta ar seju. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Seja atpazīta. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Seja atpazīta. Lai turpinātu, nospiediet atbloķēšanas ikonu."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Austiņas"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ievade"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Dzirdes aparāti"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Notiek ieslēgšana…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nevar saglabāt. Mēģiniet vēlreiz."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nevar saglabāt."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Izmantojiet vismaz 4 rakstzīmes"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Izmantojiet mazāk nekā 16 rakstzīmes"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
<string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistents klausās"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Piezīmju pierakstīšana"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Piezīmju pierakstīšana, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Notiek apraidīšana"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 1596f8b..037fd7b 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е проверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Допрете „Потврди“ за да се заврши"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Отклучено со лице."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Отклучено со лик. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицето е препознаено. Притиснете за да продолжите."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицето е препознаено. Притиснете ја иконата за отклучување за да продолжите."</string>
@@ -173,12 +174,12 @@
<string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"Поставување „Отклучување со отпечаток“"</string>
<string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"За да поставите „Отклучување со отпечаток“ повторно, вашите сегашни слики и модели на отпечаток ќе се избришат.\n\nОткако ќе се избришат, ќе треба повторно да поставите „Отклучување со отпечаток“ за да го користите отпечатокот за отклучување на телефонот или потврда дека сте вие."</string>
<string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"За да поставите „Отклучување со отпечаток“ повторно, вашите сегашните слики и модели на отпечаток ќе бидат избришат.\n\nОткако ќе се избришат, ќе треба повторно да поставите „Отклучување со отпечаток“ за да го користите отпечатокот за да го отклучите телефонот или да потврдите дека сте вие."</string>
- <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Не можеше да се постави „Отклучување со отпечаток“. Одете во „Поставки“ за да се обидете повторно."</string>
+ <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Не можеше да се постави „Отклучување со отпечаток“. Отворете „Поставки“ за да се обидете повторно."</string>
<string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Поставете „Отклучување со лик“ повторно"</string>
<string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Отклучување со лик"</string>
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Поставување „Отклучување со лик“"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"За да може одново да поставите „Отклучување со лик“, вашиот сегашен модел на лик ќе се избрише.\n\nЗа да го користите ликот за отклучување на телефонот, ќе треба повторно да ја поставите функцијава."</string>
- <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не можеше да се постави „Отклучување со лик“. Одете во „Поставки“ за да се обидете повторно."</string>
+ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не можеше да се постави „Отклучување со лик“. Отворете „Поставки“ за да се обидете повторно."</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Допрете го сензорот за отпечатоци"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Слушни помагала"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не може да се зачува. Обидете се повторно."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не може да се зачува."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Употребете најмалку 4 знаци"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Употребете помалку од 16 знаци"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"„Помошникот“ слуша"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известување}one{# известување}other{# известувања}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Фаќање белешки"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Фаќање белешки, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитување"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се прекине емитувањето на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитувате на <xliff:g id="SWITCHAPP">%1$s</xliff:g> или го промените излезот, тековното емитување ќе запре"</string>
@@ -1148,7 +1149,7 @@
<string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</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_text" msgid="2856337395968118274">"Вашата организација ви дозволува да упатувате повици само од работни апликации"</string>
<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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 09cb9bf..e8ec2a4 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"സ്ഥിരീകരിച്ചു"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"പൂർത്തിയാക്കാൻ സ്ഥിരീകരിക്കുക ടാപ്പ് ചെയ്യൂ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്തിരിക്കുന്നു."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്തു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"മുഖം തിരിച്ചറിഞ്ഞു. തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ശ്രവണ സഹായികൾ"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"സംരക്ഷിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"സംരക്ഷിക്കാൻ കഴിയില്ല."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"കുറഞ്ഞത് 4 പ്രതീകങ്ങളെങ്കിലും ഉപയോഗിക്കുക"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16-ൽ കുറവ് പ്രതീകങ്ങൾ ഉപയോഗിക്കുക"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant കേൾക്കുന്നു"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"കുറിപ്പ് രേഖപ്പെടുത്തൽ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"പ്രക്ഷേപണം ചെയ്യുന്നു"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്കാസ്റ്റ് അവസാനിക്കും"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 1f24255..21257ac 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Царайг баталгаажууллаа"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Баталгаажсан"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Дуусгахын тулд баталгаажуулахыг товших"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Царайгаар түгжээг тайлсан."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Царайг таньсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Царайг таньсан. Үргэлжлүүлэх бол түгжээг тайлах дүрсийг дар."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Сонсголын төхөөрөмж"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Хадгалах боломжгүй. Дахин оролдоно уу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Хадгалах боломжгүй."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Дор хаяж 4 тэмдэгт ашиглана уу."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16-аас цөөн тэмдэгт ашиглана уу"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Туслах сонсож байна"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Тэмдэглэл хөтлөх"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Тэмдэглэл хөтлөх, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Нэвтрүүлэлт"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index db3585d..8c7eec4 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"चेहऱ्याने अनलॉक केले आहे."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"श्रवणयंत्रे"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेव्ह करू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेव्ह करू शकत नाही."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"किमान चार वर्ण वापरा"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"१६ पेक्षा कमी वर्ण वापरा"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant ऐकत आहे"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"नोंद घेणे"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोंद घेणे, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट करत आहे"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6708af6f..8eadbb6 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah disahkan"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Disahkan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketik Sahkan untuk menyelesaikan"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Dibuka kunci dengan wajah."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Dibuka kunci dengan wajah. Tekan untuk meneruskan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Wajah dicam. Tekan untuk meneruskan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Wajah dicam. Tekan ikon buka kunci untuk meneruskan."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Set Kepala"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Alat Bantu Dengar"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Menghidupkan…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Tidak dapat disimpan. Cuba lagi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Tidak dapat disimpan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gunakan sekurang-kurangnya 4 aksara"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Gunakan kurang daripada 16 aksara"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
<string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Pembantu sedang mendengar"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pemberitahuan}other{# pemberitahuan}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pengambilan nota"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pengambilan nota, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index fff12368..7fe03b3 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"အတည်ပြုပြီးပြီ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"အပြီးသတ်ရန်အတွက် \'အတည်ပြုရန်\' ကို တို့ပါ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"မျက်နှာဖြင့် ဖွင့်ထားသည်။"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"မျက်နှာဖြင့် ဖွင့်ထားသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"မျက်နှာ မှတ်မိသည်။ ရှေ့ဆက်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ။"</string>
@@ -243,7 +244,7 @@
<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="3003338571871392293">"နားကြားကိရိယာ"</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>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"သိမ်း၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"သိမ်း၍မရပါ။"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"အနည်းဆုံး အက္ခရာ ၄ လုံး သုံးရန်"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"အက္ခရာ ၁၆ လုံးအောက် သုံးရန်"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant နားထောင်နေသည်"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>၊ <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"မှတ်စုလိုက်ခြင်း"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"မှတ်စုလိုက်ခြင်း၊ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ထုတ်လွှင့်ခြင်း"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 24f7cb1..369f6af 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet er autentisert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekreftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trykk på Bekreft for å fullføre"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Låst opp med ansiktet."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Låst opp med ansiktet. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet er gjenkjent. Trykk for å fortsette."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet er gjenkjent. Trykk på lås opp-ikon for å fortsette"</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Hodetelefoner"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Innenhet"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Høreapparater"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Slår på …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan ikke lagre. Prøv på nytt."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan ikke lagre."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Bruk minst 4 tegn"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Bruk færre enn 16 tegn"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistenten lytter"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Notatskriving"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notatskriving, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Kringkaster"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 5c6e846..69ee5eb 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"अनुहार प्रमाणीकरण गरियो"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि भयो"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूरा गर्नका लागि पुष्टि गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"अनुहार प्रयोग गरी अनलक गरियो।"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न थिच्नुहोस्।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"अनुहार पहिचान गरियो। जारी राख्न थिच्नुहोस्।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"अनुहार पहिचान गरियो। जारी राख्न अनलक आइकनमा थिच्नुहोस्।"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"श्रवण यन्त्रहरू"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"सेभ गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"सेभ गर्न सकिएन।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"कम्तीमा ४ वटा वर्ण प्रयोग गर्नुहोस्"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"१६ वटाभन्दा कम वर्ण प्रयोग गर्नुहोस्"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"सहायकले सुनिरहेको छ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"नोट लेख्ने कार्य"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोट लेख्ने कार्य, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"प्रसारण गरिँदै छ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c4d6f68..b5a6642 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gezicht geverifieerd"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestigd"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestigen om te voltooien"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Ontgrendeld via gezicht."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Ontgrendeld via gezicht. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Gezicht herkend. Druk om door te gaan."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Gezicht herkend. Druk op het ontgrendelicoon."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hoortoestellen"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aanzetten…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kan niet opslaan. Probeer het opnieuw."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kan niet opslaan."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gebruik minstens 4 tekens"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Gebruik minder dan 16 tekens"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
<string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"De Assistent luistert"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Aantekeningen maken"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Aantekeningen maken, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitzending"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 428e42b..76bafc6 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ମୁହଁ ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ସୁନିଶ୍ଚିତ କରାଯାଇଛି"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ସୁନିଶ୍ଚିତ କରନ୍ତୁରେ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି।"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ଫେସ ଚିହ୍ନଟ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ।"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -296,7 +298,7 @@
<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_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>
@@ -414,7 +416,7 @@
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ଦ୍ୱାରା ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"ଡିଭାଇସ ନୀତି ଦ୍ୱାରା ସ୍କ୍ରିନ କେପଚରିଂକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ଇତିହାସ"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"ନୂଆ"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ସେଭ କରାଯାଇପାରିଲା ନାହିଁ।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ଅତିକମରେ 4ଟି କେରେକ୍ଟର ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16ଟିରୁ କମ କେରେକ୍ଟର ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant ଶୁଣୁଛି"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"ନୋଟ-ଟେକିଂ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ନୋଟ-ଟେକିଂ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ବ୍ରଡକାଷ୍ଟ କରୁଛି"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index cda538f..0751dd2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਿਰਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ਪੁਸ਼ਟੀ ਕੀਤੀ ਗਈ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ਪੂਰਾ ਕਰਨ ਲਈ ਪੁਸ਼ਟੀ ਕਰੋ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ਚਿਹਰੇ ਰਾਹੀਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਹੋਈ। ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ।"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ਘੱਟੋ-ਘੱਟ 4 ਅੱਖਰ-ਚਿੰਨ੍ਹ ਵਰਤੋ"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 ਤੋਂ ਘੱਟ ਅੱਖਰ-ਚਿੰਨ੍ਹ ਵਰਤੋ"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant ਸੁਣ ਰਹੀ ਹੈ"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"ਨੋਟ ਬਣਾਉਣਾ"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ਨੋਟ ਬਣਾਉਣਾ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ਪ੍ਰਸਾਰਨ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f857641..5f81863 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Twarz rozpoznana"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potwierdzono"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Aby zakończyć, kliknij Potwierdź"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Odblokowano skanem twarzy."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odblokowano rozpoznawaniem twarzy. Kliknij, aby kontynuować."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Twarz rozpoznana. Kliknij, aby kontynuować."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Twarz rozpoznana. Aby kontynuować, kliknij ikonę odblokowywania."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Zestaw słuchawkowy"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Wejście"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparaty słuchowe"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Włączam…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nie można zapisać. Spróbuj ponownie."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nie można zapisać."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Wpisz co najmniej 4 znaki"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Wpisz mniej niż 16 znaków"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
<string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asystent słucha"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Notatki"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notatki, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmisja"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e73fba7..9a44a53 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Desbloqueado pelo rosto."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparelhos auditivos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
@@ -989,7 +991,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
- <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Opções de dispositivos"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Interrompa sua sessão compartilhada para transferir mídia a outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Parar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use pelo menos 4 caracteres"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use menos de 16 caracteres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"O Google Assistente está ouvindo"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Anotações"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anotações, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ef0ae9a8..9e80b25 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em Confirmar para concluir."</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Desbloqueado com o rosto."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado com o rosto. Prima para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Prima para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Prima ícone de desbloqueio para continuar"</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ausc. c/ mic. integ."</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparelhos auditivos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"A ativar..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Não é possível guardar. Tente novamente."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Não é possível guardar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use, pelo menos, 4 carateres"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use menos de 16 carateres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"O Assistente está a ouvir"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Tomar notas"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Tomar notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e73fba7..9a44a53 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Desbloqueado pelo rosto."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Desbloqueado pelo rosto. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Pressione para continuar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Pressione o ícone para continuar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparelhos auditivos"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
@@ -989,7 +991,7 @@
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
- <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Opções de dispositivos"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Interrompa sua sessão compartilhada para transferir mídia a outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Parar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Falha ao salvar. Tente de novo."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Falha ao salvar."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Use pelo menos 4 caracteres"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Use menos de 16 caracteres"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"O Google Assistente está ouvindo"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Anotações"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anotações, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 900b1f9..b05eee0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Chip autentificat"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atinge Confirm pentru a finaliza"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"S-a deblocat folosind fața."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S-a deblocat cu ajutorul feței. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Chipul a fost recunoscut. Apasă pentru a continua."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apasă pictograma Deblocare ca să continui."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Căști"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Intrare"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparate auditive"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Se activează..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
@@ -988,7 +990,7 @@
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispozitive disponibile pentru ieșire audio."</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
- <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Difuzoare și afișaje"</string>
+ <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Difuzoare și ecrane"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispozitive sugerate"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Oprește sesiunea comună ca să muți elementul media pe alt dispozitiv"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Oprește"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nu se poate salva. Încearcă din nou."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nu se poate salva."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Folosește minimum 4 caractere."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Folosește maximum 16 caractere"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Deschide conversația"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistentul ascultă"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Luare de notițe"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Luare de notițe, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Se difuzează"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Oprești transmisia <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă transmiți <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbi ieșirea, transmisia actuală se va opri"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6ad3402..c342928 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицо распознано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Подтверждено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Нажмите \"Подтвердить\""</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Разблокировано сканированием лица."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Разблокировано сканированием лица. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лицо распознано. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лицо распознано. Нажмите на значок разблокировки."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Слуховые аппараты"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не удалось сохранить. Повторите попытку."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не удалось сохранить."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Минимальное количество символов – 4"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Максимальное количество символов – 16"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Ассистент вас слушает"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# уведомление}one{# уведомление}few{# уведомления}many{# уведомлений}other{# уведомления}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Создание заметок"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>: создание заметок"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляция"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Остановить трансляцию \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Если вы начнете транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" или смените целевое устройство, текущая трансляция прервется."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index fd07fa7..633d5d8 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"මුහුණ සත්යාපන කළා"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"තහවුරු කළා"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"සම්පූර්ණ කිරීමට තහවුරු කරන්න තට්ටු කර."</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"මුහුණ මගින් අගුළු හරින ලදි."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"මුහුණ මගින් අගුලු හරින ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"මුහුණ හඳුනා ගන්නා ලදි. ඉදිරියට යාමට අගුලු හැරීමේ නිරූපකය ඔබන්න."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"ශ්රවණාධාරක"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"සුරැකිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"සුරැකිය නොහැකිය."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"අවම වශයෙන් අනුලකුණු 4ක් භාවිතා කරන්න"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"අනුලකුණු 16කට වඩා අඩුවෙන් භාවිතා කරන්න"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"සහයක සවන් දෙයි"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"සටහන් කර ගැනීම"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"සටහන් කර ගැනීම, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"විකාශනය කරමින්"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 51f166a..6764568 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Tvár bola overená"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrdené"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Overenie dokončíte klepnutím na Potvrdiť"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Odomknuté tvárou."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odomknuté tvárou. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Tvár bola rozpoznaná. Pokračujte stlačením."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Tvár bola rozpoznaná. Pokračujte stlačením ikony odomknutia"</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Náhlavná súprava"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Načúvadlá"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapína sa…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nedá sa uložiť. Skúste to znova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nedá sa uložiť."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Použite aspoň štyri znaky"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Použite menej než 16 znakov"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistent počúva"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# upozornenie}few{# upozornenia}many{# notifications}other{# upozornení}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Zapisovanie poznámok"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Zapisovanie poznámok, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysiela"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Chcete zastaviť vysielanie aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ak vysielate aplikáciu <xliff:g id="SWITCHAPP">%1$s</xliff:g> alebo zmeníte výstup, aktuálne vysielanie bude zastavené"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 51f4c4e..2cbf0b6 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Pristnost obraza je potrjena"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potrjeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Za dokončanje se dotaknite »Potrdite«"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Odklenjeno z obrazom."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Odklenjeno z obrazom. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Obraz je prepoznan. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Obraz je prepoznan. Za nadaljevanje pritisnite ikono za odklepanje."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvok"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalke z mikrofonom"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Slušni pripomočki"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Vklapljanje …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ni mogoče shraniti. Poskusite znova."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ni mogoče shraniti."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Uporabite vsaj 4 znake."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Uporabite manj kot 16 znakov."</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
<string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Pomočnik posluša."</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Ustvarjanje zapiskov"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ustvarjanje zapiskov, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Oddajanje"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 9905a6f..8d87277 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Fytyra u vërtetua"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Konfirmuar"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trokit \"Konfirmo\" për ta përfunduar"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"U shkyç me fytyrë."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"U shkyç me fytyrë. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Fytyra u njoh. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Fytyra u njoh. Shtyp ikonën e shkyçjes për të vazhduar."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kufje me mikrofon"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Hyrja"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Aparatet e dëgjimit"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Po aktivizohet…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Nuk mund të ruhet. Provo përsëri."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Nuk mund të ruhet."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Përdor të paktën 4 karaktere"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Përdor më pak se 16 karaktere"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
<string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"\"Asistenti\" po dëgjon"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# njoftim}other{# njoftime}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Mbajtja e shënimeve"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Mbajtja e shënimeve, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Po transmeton"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Të ndalohet transmetimi i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nëse transmeton <xliff:g id="SWITCHAPP">%1$s</xliff:g> ose ndryshon daljen, transmetimi yt aktual do të ndalojë"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5885c10..1206198 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лице је потврђено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврђено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Додирните Потврди да бисте завршили"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Откључано је лицем."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Откључано је лицем. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Лице је препознато. Притисните да бисте наставили."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Лице препознато. Притисните икону откључавања за наставак."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Слушни апарати"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Чување није успело. Пробајте поново."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Чување није успело."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Користите бар 4 знака"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Користите мање од 16 знакова"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Помоћник слуша"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# обавештење}one{# обавештење}few{# обавештења}other{# обавештења}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Прављење бележака"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Прављење бележака, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитовање"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Желите да зауставите емитовање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитујете апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените излаз, актуелно емитовање ће се зауставити"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index be35743..1e776d1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet har autentiserats"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekräftat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Upplåst med ansiktslås."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Upplåst med ansiktslås. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ansiktet har identifierats. Tryck för att fortsätta."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ansiktet har identifierats. Tryck på ikonen lås upp."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ljud"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingång"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hörapparater"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverar …"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Det gick inte att spara. Försök igen."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Det gick inte att spara."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Använd minst 4 tecken"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Använd färre än 16 tecken"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
<string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistenten lyssnar"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Anteckna"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anteckna med <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sänder"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fae139cb..38987fa 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Uso umethibitishwa"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Imethibitishwa"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Gusa Thibitisha ili ukamilishe"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Imefunguka kwa kutumia uso wako."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Uso umetambuliwa. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Uso umetambuliwa. Bonyeza aikoni ya kufungua ili uendelee."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Vifaa vya sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vifaa vya kuingiza sauti"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Visaidizi vya Kusikia"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inawasha..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Imeshindwa kuhifadhi. Jaribu tena."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Imeshindwa kuhifadhi."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Tumia angalau herufi 4"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Tumia herufi chini ya 16"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
<string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Programu ya Mratibu inasikiliza"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Arifa #}other{Arifa #}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Kuandika madokezo"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Kuandika madokezo, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Inaarifu"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ungependa kusimamisha utangazaji kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ikiwa unatangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g> au unabadilisha maudhui, tangazo lako la sasa litasimamishwa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0492245..1e883e6 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"முகம் அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"முகம் மூலம் அன்லாக் செய்யப்பட்டது."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"முகம் மூலம் அன்லாக் செய்யப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அழுத்தவும்."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"முகம் அங்கீகரிக்கப்பட்டது. தொடர அன்லாக் ஐகானை அழுத்தவும்."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"செவித்துணை கருவிகள்"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"சேமிக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"சேமிக்க முடியவில்லை."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"குறைந்தது 4 எழுத்துகளைப் பயன்படுத்துங்கள்"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 எழுத்துகளுக்குக் குறைவாகப் பயன்படுத்துங்கள்"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant கேட்டுக்கொண்டிருக்கிறது"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"குறிப்பெடுத்தல்"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"குறிப்பெடுத்தல், <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ஒலிபரப்புதல்"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 4572fac..ffe4b17 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ముఖం ప్రామాణీకరించబడింది"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"నిర్ధారించబడింది"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"పూర్తి చేయడానికి \"నిర్ధారించు\" నొక్కండి"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ముఖం ద్వారా అన్లాక్ చేయబడింది."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ముఖం ద్వారా అన్లాక్ చేయబడింది. కొనసాగించడానికి నొక్కండి."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"ముఖం గుర్తించబడింది. కొనసాగించడానికి నొక్కండి."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"ముఖం గుర్తించబడింది. కొనసాగడానికి అన్లాక్ చిహ్నం నొక్కండి."</string>
@@ -243,7 +244,7 @@
<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="3003338571871392293">"వినికిడి పరికరాలు"</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>
@@ -389,7 +390,7 @@
<string name="guest_notification_session_active" msgid="5567273684713471450">"మీరు గెస్ట్ మోడ్లో ఉన్నారు"</string>
<string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"కొత్త యూజర్ను జోడించడం వలన గెస్ట్ మోడ్ నుండి వైదొలుగుతుంది. అలాగే ప్రస్తుత గెస్ట్ సెషన్ నుండి అన్ని యాప్లతో పాటు మొత్తం డేటా తొలగించబడుతుంది."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string>
- <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{ఒక యూజర్ను మాత్రమే క్రియేట్ చేయవచ్చు.}other{మీరు గరిష్టంగా # మంది యూజర్లను జోడించవచ్చు.}}"</string>
+ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{ఒక యూజర్ను మాత్రమే క్రియేట్ చేయవచ్చు.}other{మీరు గరిష్ఠంగా # మంది యూజర్లను జోడించవచ్చు.}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"యూజర్ను తీసివేయాలా?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"ఈ వినియోగదారుకు సంబంధించిన అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"తీసివేయండి"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"సేవ్ చేయడం సాధ్యపడదు. మళ్లీ ట్రై చేయండి."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"సేవ్ చేయడం సాధ్యపడదు."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"కనీసం 4 అక్షరాలను ఉపయోగించండి"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 కంటే తక్కువ అక్షరాలను ఉపయోగించండి"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant వింటోంది"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్లు}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"నోట్-టేకింగ్"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"నోట్-టేకింగ్, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ప్రసారం చేస్తోంది"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్పుట్ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 0ca154e..2ace86f 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -20,11 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- SystemUIFactory component -->
- <string name="config_systemUIFactoryComponent" translatable="false">
- com.android.systemui.tv.TvSystemUIInitializer
- </string>
-
<!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
<integer name="recents_svelte_level">3</integer>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ad1128b..f408508 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ยืนยันแล้ว"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"แตะยืนยันเพื่อดำเนินการให้เสร็จสมบูรณ์"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"ปลดล็อกด้วยใบหน้าแล้ว"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"ปลดล็อกด้วยใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"จดจำใบหน้าได้ กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"จดจำใบหน้าได้ กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"เครื่องช่วยฟัง"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"บันทึกไม่ได้ โปรดลองอีกครั้ง"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"บันทึกไม่ได้"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"ใช้อักขระอย่างน้อย 4 ตัว"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"ใช้อักขระไม่เกิน 16 ตัว"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistant กำลังฟังอยู่"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"การจดบันทึก"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"การจดบันทึก <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"กำลังออกอากาศ"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 80fac07..402b4f1 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Na-authenticate ang mukha"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Nakumpirma"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"I-tap ang Kumpirmahin para kumpletuhin"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Na-unlock gamit ang mukha."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Na-unlock gamit ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Nakilala ang mukha. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Nakilala ang mukha. Pindutin ang unlock para magpatuloy."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Mga Hearing Aid"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ino-on…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Hindi ma-save. Subukan ulit."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Hindi ma-save."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Gumamit ng hindi bababa sa 4 na character"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Gumamit ng mas kaunti sa 16 na character"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
<string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Nakikinig ang Assistant"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Pagtatala"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pagtatala, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Nagbo-broadcast"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 759dd29..ed3a36f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yüz kimliği doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Onaylandı"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamak için Onayla\'ya dokunun"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Cihazın kilidini yüzünüzle açtınız."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Cihazın kilidini yüzünüzle açtınız. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yüzünüz tanındı. Devam etmek için basın."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yüzünüz tanındı. Kilit açma simgesine basın."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ses"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Mikrofonlu kulaklık"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"İşitme Cihazları"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Açılıyor…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Kaydedilemiyor. Tekrar deneyin."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Kaydedilemiyor."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"En az 4 karakter kullanın."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"En fazla 16 karakter kullanın"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Asistan dinliyor"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Not alma"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Not alma, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayınlama"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4424871..e4f27a0 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Обличчя автентифіковано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Розблоковано (фейс-контроль)."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейсконтроль). Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Обличчя розпізнано. Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Обличчя розпізнано. Натисніть значок розблокування."</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"Слухові апарати"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Не вдалося зберегти. Повторіть спробу."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Не вдалося зберегти."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Введіть принаймні 4 символи"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Введіть менше ніж 16 символів"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Асистент слухає"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Створення нотаток"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Створення нотаток, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляція"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4438f1b..dceeb29 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چہرے کی تصدیق ہو گئی"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تصدیق شدہ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"مکمل کرنے کیلئے \'تصدیق کریں\' تھپتھپائیں"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"چہرے سے غیر مقفل کیا گیا۔"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"چہرے سے انلاک کیا گیا۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کے لیے دبائیں۔"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"چہرے کی شناخت ہو گئی۔ جاری رکھنے کیلئے انلاک آئیکن دبائیں۔"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"سماعتی آلات"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"محفوظ نہیں کیا جا سکا۔ پھر کوشش کریں۔"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"محفوظ نہیں کیا جا سکا۔"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"کم از کم 4 حروف استعمال کریں"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"16 حروف سے کم استعمال کریں"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"اسسٹنٹ سن رہی ہے"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اطلاع}other{# اطلاعات}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"نوٹ لکھنا"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"نوٹ لکھنا، <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"نشریات"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> براڈکاسٹنگ روکیں؟"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر آپ <xliff:g id="SWITCHAPP">%1$s</xliff:g> براڈکاسٹ کرتے ہیں یا آؤٹ پٹ کو تبدیل کرتے ہیں تو آپ کا موجودہ براڈکاسٹ رک جائے گا"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 4a24cbb..dce06aa 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yuzingiz aniqlandi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Tasdiqlangan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tasdiqlash uchun tegining"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Yuz bilan ochildi."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Yuz orqali ochildi. Davom etish uchun bosing."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Yuz aniqlandi. Davom etish uchun bosing."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Yuz aniqlandi. Davom etish uchun ochish belgisini bosing."</string>
@@ -243,7 +244,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Garnitura"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Kirish"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Eshitish apparatlari"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eshitish moslamalari"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Yoqilmoqda…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
@@ -1004,7 +1005,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Saqlanmadi. Qayta urining."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Saqlanmadi."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Parolga kamida 4 ta belgi kiriting."</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Kiritiladigan belgilar 16 tadan oshmasin"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
<string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
@@ -1108,10 +1110,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Assistent tinglamoqda"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ta bildirishnoma}other{# ta bildirishnoma}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Qayd olish"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>: qayd olish"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Signal uzatish"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga translatsiya toʻxtatilsinmi?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Agar <xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya qilsangiz yoki ovoz chiqishini oʻzgartirsangiz, joriy translatsiya toʻxtab qoladi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f58f07b..bf4c3ed 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Đã xác thực khuôn mặt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ðã xác nhận"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Nhấn vào Xác nhận để hoàn tất"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Đã mở khoá bằng khuôn mặt."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Đã mở khoá bằng khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Đã nhận diện khuôn mặt. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Đã nhận diện khuôn mặt. Nhấn biểu tượng mở khoá để tiếp tục."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Âm thanh"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Tai nghe"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Thiết bị đầu vào"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Thiết bị trợ thính"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Đang bật…"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Không lưu được. Hãy thử lại."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Không lưu được."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Sử dụng ít nhất 4 ký tự"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Sử dụng ít hơn 16 ký tự"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
<string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Trợ lý đang nghe bạn nói"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Ghi chú"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ghi chú, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Phát sóng"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 48f4f89..b43cb20 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔身份验证成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已确认"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"点按“确认”即可完成"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"已用面孔解锁"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已通过面孔识别解锁。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"识别出面孔。点按即可继续。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"识别出面孔。按下解锁图标即可继续。"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"助听器"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"无法保存,请重试。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"无法保存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"必须至少 4 个字符"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"必须少于 16 个字符"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build 号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将 Build 号复制到剪贴板。"</string>
<string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Google 助理正在聆听"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"记事"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"记事,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"正在广播"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e1f591b..89876ff 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔已經驗證"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"已使用面孔解鎖。"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"已使用面孔解鎖。按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"已識別面孔。按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"已識別面孔。按解鎖圖示即可繼續。"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"助聽器"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"請至少使用 4 個字元"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"請使用少於 16 個字元"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"「Google 助理」正在聆聽"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"做筆記"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"做筆記,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index dc0ac09..baf157f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔驗證成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認完畢"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕觸 [確認] 完成驗證設定"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"裝置已由人臉解鎖。"</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"裝置已透過你的臉解鎖,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"臉孔辨識完成,按下即可繼續操作。"</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"臉孔辨識完成,按下「解鎖」圖示即可繼續操作。"</string>
@@ -243,7 +244,8 @@
<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="3003338571871392293">"助聽器"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<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>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"無法儲存,請再試一次。"</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"無法儲存。"</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"至少要有 4 個半形字元"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"不得超過 16 個半形字元"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<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>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"Google 助理正在聆聽"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"做筆記"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"做筆記,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9e34437..46b9a6c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -142,7 +142,8 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ubuso bufakazelwe ubuqiniso"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kuqinisekisiwe"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Thepha okuthi Qinisekisa ukuze uqedele"</string>
- <string name="biometric_dialog_tap_confirm_with_face" msgid="3783056044917913453">"Kuvulwe ngobuso."</string>
+ <!-- no translation found for biometric_dialog_tap_confirm_with_face (2378151312221818694) -->
+ <skip />
<string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Vula ngobuso. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Ubuso buyaziwa. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Ubuso buyaziwa. Cindezela isithonjana sokuvula ukuze uqhubeke."</string>
@@ -243,7 +244,8 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Umsindo"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ihedisethi"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Okokufaka"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Izinsiza zokuzwa"</string>
+ <!-- no translation found for quick_settings_bluetooth_secondary_label_hearing_aids (5553051568867097111) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Iyavula..."</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
@@ -1004,7 +1006,8 @@
<string name="media_output_broadcast_update_error" msgid="1420868236079122521">"Ayikwazi ukulondoloza. Zama futhi."</string>
<string name="media_output_broadcast_last_update_error" msgid="5484328807296895491">"Ayikwazi ukulondoloza."</string>
<string name="media_output_broadcast_code_hint_no_less_than_min" msgid="4663836092607696185">"Sebenzisa okungenani izinhlamvu ezi-4"</string>
- <string name="media_output_broadcast_code_hint_no_more_than_max" msgid="9181869364856175638">"Sebenzisa isinhlamvu ezimbalwa kuneziyi-16"</string>
+ <!-- no translation found for media_output_broadcast_edit_hint_no_more_than_max (3923625800037673922) -->
+ <skip />
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
<string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
@@ -1108,10 +1111,8 @@
<string name="dream_overlay_status_bar_assistant_attention_indicator" msgid="4712565923771372690">"I-Assistant ilalele"</string>
<string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string>
<string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
- <!-- no translation found for note_task_button_label (230135078402003532) -->
- <skip />
- <!-- no translation found for note_task_shortcut_long_label (7729325091147319409) -->
- <skip />
+ <string name="note_task_button_label" msgid="230135078402003532">"Ukuthatha amanothi"</string>
+ <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ukuthatha amanothi, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
<string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Ukusakaza"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c3651cf..421f41f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -302,9 +302,6 @@
<!-- Determines whether the shell features all run on another thread. -->
<bool name="config_enableShellMainThread">true</bool>
- <!-- SystemUIFactory component -->
- <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIInitializerImpl</string>
-
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
<dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
<dimen name="config_qsTileStrokeWidthInactive">-1dp</dimen>
@@ -902,4 +899,16 @@
<!-- Time (in ms) to delay the bouncer views from showing when passive auth may be used for
device entry. -->
<integer name="primary_bouncer_passive_auth_delay">500</integer>
+
+ <!--
+ The package name of the app store app. If empty, features using this should be gracefully
+ disabled.
+ -->
+ <string name="config_appStorePackageName" translatable="false"></string>
+
+ <!-- Template for a link that leads to an app page in the relevant app store. If empty,
+ features using this should be gracefully disabled. If not empty, it must include a
+ "$packageName" part that will be replaced by the code with the package name of the target app.
+ -->
+ <string name="config_appStoreAppLinkTemplate" translatable="false"></string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 50d33c6..da6417d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -575,6 +575,7 @@
<dimen name="qs_brightness_margin_bottom">16dp</dimen>
<dimen name="qqs_layout_margin_top">16dp</dimen>
<dimen name="qqs_layout_padding_bottom">24dp</dimen>
+ <item name="qqs_expand_clock_scale" format="float" type="dimen">2.57</item>
<!-- Most of the time it should be the same as notification_side_paddings as it's vertically
aligned with notifications. The exception is split shade when this value becomes
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9108fa6..25f3d22 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2817,6 +2817,8 @@
<!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] -->
<string name="qs_alarm_tile_no_alarm">No alarm set</string>
+ <!-- Accessibility label for a11y action to show the bouncer (pin/pattern/password) screen lock [CHAR LIMIT=NONE] -->
+ <string name="accessibility_bouncer">enter screen lock</string>
<!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_label">Fingerprint sensor</string>
<!-- Accessibility action for tapping on an affordance that will bring up the user's
@@ -3020,52 +3022,54 @@
-->
<string name="keyguard_affordance_enablement_dialog_action_template">Open <xliff:g id="appName" example="Wallet">%1$s</xliff:g></string>
- <!--
- Requirement for the wallet app to be available for the user to use. This is shown as part of a
- bulleted list of requirements. When all requirements are met, the app can be accessed through a
- shortcut button on the lock screen. [CHAR LIMIT=NONE].
+ <!---
+ Explains that the wallet app is not available because it is not installed. This is shown as part
+ of a dialog that explains to the user why they cannot select this shortcut for their lock screen
+ right now.
+ [CHAR LIMIT=NONE].
-->
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1">• The app is set up</string>
+ <string name="wallet_quick_affordance_unavailable_install_the_app">To add the Wallet app as a shortcut, make sure the app is installed</string>
- <!--
- Requirement for the wallet app to be available for the user to use. This is shown as part of a
- bulleted list of requirements. When all requirements are met, the app can be accessed through a
- shortcut button on the lock screen. [CHAR LIMIT=NONE].
+ <!---
+ Explains that the wallet app is not available because it is not installed. This is shown as part
+ of a dialog that explains to the user why they cannot select this shortcut for their lock screen
+ right now.
+ [CHAR LIMIT=NONE].
-->
- <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2">• At least one card has been added to Wallet</string>
+ <string name="wallet_quick_affordance_unavailable_configure_the_app">To add the Wallet app as a shortcut, make sure at least one card has been added</string>
<!--
Requirement for the QR code scanner functionality to be available for the user to use. This is
shown as part of a bulleted list of requirements. When all requirements are met, the piece of
functionality can be accessed through a shortcut button on the lock screen. [CHAR LIMIT=NONE].
-->
- <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction">• Install a camera app</string>
+ <string name="qr_scanner_quick_affordance_unavailable_explanation">To add the QR code scanner as a shortcut, make sure a camera app is installed</string>
<!--
- Requirement for the home app to be available for the user to use. This is shown as part of a
- bulleted list of requirements. When all requirements are met, the app can be accessed through a
- shortcut button on the lock screen. [CHAR LIMIT=NONE].
+ Explains that the lock screen shortcut for the "home" app is not available because the app isn't
+ installed. This is shown as part of a dialog that explains to the user why they cannot select
+ this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
-->
- <string name="keyguard_affordance_enablement_dialog_home_instruction_1">• The app is set up</string>
+ <string name="home_quick_affordance_unavailable_install_the_app">To add the Home app as a shortcut, make sure the app is installed</string>
<!--
- Requirement for the home app to be available for the user to use. This is shown as part of a
- bulleted list of requirements. When all requirements are met, the app can be accessed through a
- shortcut button on the lock screen. [CHAR LIMIT=NONE].
+ Explains that the lock screen shortcut for the "home" app is not available because the app isn't
+ configured. This is shown as part of a dialog that explains to the user why they cannot select
+ this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
-->
- <string name="keyguard_affordance_enablement_dialog_home_instruction_2">• At least one device is available</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app">• At least one device is available</string>
<!---
- Requirement for the notes app to be available for the user to use. This is shown as part of a
- bulleted list of requirements. When all requirements are met, the app can be accessed through a
- shortcut button on the lock screen. [CHAR LIMIT=NONE] -->
- <string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use the notetaking shortcut</string>
+ Explains that the notes app is not available. This is shown as part of a dialog that explains to
+ the user why they cannot select this shortcut for their lock screen right now.
+ [CHAR LIMIT=NONE].
+ -->
+ <string name="notes_app_quick_affordance_unavailable_explanation">Select a default notes app to use the notetaking shortcut</string>
<!---
The action to make the lock screen shortcut for the notes app to be available for the user to
- use. This is shown as the action button in the dialog listing the requirements. When all
- requirements are met, the app can be accessed through a shortcut button on the lock screen.
- [CHAR LIMIT=NONE] -->
+ use. This is shown as the action button in the dialog explaining why the shortcut isn't
+ available. [CHAR LIMIT=NONE] -->
<string name="keyguard_affordance_enablement_dialog_notes_app_action">Select app</string>
<!--
@@ -3157,4 +3161,11 @@
<!--- Content of toast triggered when the notes app entry point is triggered without setting a default notes app. [CHAR LIMIT=NONE] -->
<string name="set_default_notes_app_toast_content">Set default notes app in Settings</string>
+
+ <!--
+ Label for a button that, when clicked, sends the user to the app store to install an app.
+
+ [CHAR LIMIT=64].
+ -->
+ <string name="install_app">Install app</string>
</resources>
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index 52a98984..8039c68 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -43,8 +43,8 @@
app:layout_constraintBottom_toBottomOf="@id/carrier_group"
/>
<Transform
- android:scaleX="2.57"
- android:scaleY="2.57"
+ android:scaleX="@dimen/qqs_expand_clock_scale"
+ android:scaleY="@dimen/qqs_expand_clock_scale"
/>
</Constraint>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
index c5979cc..7a8c82c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
@@ -65,8 +65,8 @@
} else {
1
}
- viewsToTranslate.forEach { (view, direction) ->
- view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier
+ viewsToTranslate.forEach { (view, direction, func) ->
+ view.get()?.let { func(it, xTrans * direction.multiplier * rtlMultiplier) }
}
}
@@ -77,7 +77,7 @@
.filter { it.shouldBeAnimated() }
.mapNotNull {
parent.findViewById<View>(it.viewId)?.let { view ->
- ViewToTranslate(WeakReference(view), it.direction)
+ ViewToTranslate(WeakReference(view), it.direction, it.translateFunc)
}
}
.toList()
@@ -91,14 +91,19 @@
data class ViewIdToTranslate(
val viewId: Int,
val direction: Direction,
- val shouldBeAnimated: () -> Boolean = { true }
+ val shouldBeAnimated: () -> Boolean = { true },
+ val translateFunc: (View, Float) -> Unit = { view, value -> view.translationX = value },
)
/**
* Represents a view whose animation process is in-progress. It should be immutable because the
* started animation should be completed.
*/
- private data class ViewToTranslate(val view: WeakReference<View>, val direction: Direction)
+ private data class ViewToTranslate(
+ val view: WeakReference<View>,
+ val direction: Direction,
+ val translateFunc: (View, Float) -> Unit,
+ )
/** Direction of the animation. */
enum class Direction(val multiplier: Float) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Monitor.java b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Monitor.java
index 1f61c64..97d6099 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Monitor.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Monitor.java
@@ -215,7 +215,7 @@
mSubscriptions.put(token, state);
// Add and associate conditions.
- normalizedCondition.getConditions().stream().forEach(condition -> {
+ normalizedCondition.getConditions().forEach(condition -> {
if (!mConditions.containsKey(condition)) {
mConditions.put(condition, new ArraySet<>());
condition.addCallback(mConditionCallback);
@@ -321,7 +321,6 @@
private final Callback mCallback;
private final Subscription mNestedSubscription;
private final ArraySet<Condition> mConditions;
- private final ArraySet<Condition> mPreconditions;
/**
* Default constructor specifying the {@link Callback} for the {@link Subscription}.
@@ -337,8 +336,7 @@
private Builder(Subscription nestedSubscription, Callback callback) {
mNestedSubscription = nestedSubscription;
mCallback = callback;
- mConditions = new ArraySet();
- mPreconditions = new ArraySet();
+ mConditions = new ArraySet<>();
}
/**
@@ -352,29 +350,6 @@
}
/**
- * Adds a set of {@link Condition} to be a precondition for {@link Subscription}.
- *
- * @return The updated {@link Builder}.
- */
- public Builder addPreconditions(Set<Condition> condition) {
- if (condition == null) {
- return this;
- }
- mPreconditions.addAll(condition);
- return this;
- }
-
- /**
- * Adds a {@link Condition} to be a precondition for {@link Subscription}.
- *
- * @return The updated {@link Builder}.
- */
- public Builder addPrecondition(Condition condition) {
- mPreconditions.add(condition);
- return this;
- }
-
- /**
* Adds a set of {@link Condition} to be associated with the {@link Subscription}.
*
* @return The updated {@link Builder}.
@@ -394,11 +369,7 @@
* @return The resulting {@link Subscription}.
*/
public Subscription build() {
- final Subscription subscription =
- new Subscription(mConditions, mCallback, mNestedSubscription);
- return !mPreconditions.isEmpty()
- ? new Subscription(mPreconditions, null, subscription)
- : subscription;
+ return new Subscription(mConditions, mCallback, mNestedSubscription);
}
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 9a9a242..6b67c09 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -79,17 +79,26 @@
/** Alerts listener and plugin that the plugin has been created. */
public void onCreate() {
- mListener.onPluginAttached(this);
+ boolean loadPlugin = mListener.onPluginAttached(this);
+ if (!loadPlugin) {
+ if (mPlugin != null) {
+ unloadPlugin();
+ }
+ return;
+ }
+
if (mPlugin == null) {
loadPlugin();
- } else {
- if (!(mPlugin instanceof PluginFragment)) {
- // Only call onCreate for plugins that aren't fragments, as fragments
- // will get the onCreate as part of the fragment lifecycle.
- mPlugin.onCreate(mAppContext, mPluginContext);
- }
- mListener.onPluginLoaded(mPlugin, mPluginContext, this);
+ return;
}
+
+ mPluginFactory.checkVersion(mPlugin);
+ if (!(mPlugin instanceof PluginFragment)) {
+ // Only call onCreate for plugins that aren't fragments, as fragments
+ // will get the onCreate as part of the fragment lifecycle.
+ mPlugin.onCreate(mAppContext, mPluginContext);
+ }
+ mListener.onPluginLoaded(mPlugin, mPluginContext, this);
}
/** Alerts listener and plugin that the plugin is being shutdown. */
@@ -118,6 +127,7 @@
return;
}
+ mPluginFactory.checkVersion(mPlugin);
if (!(mPlugin instanceof PluginFragment)) {
// Only call onCreate for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle.
@@ -205,12 +215,8 @@
PluginFactory<T> pluginFactory = new PluginFactory<T>(
context, mInstanceFactory, appInfo, componentName, mVersionChecker, pluginClass,
() -> getClassLoader(appInfo, mBaseClassLoader));
- // TODO: Only create the plugin before version check if we need it for
- // legacy version check.
- T instance = pluginFactory.createPlugin();
- pluginFactory.checkVersion(instance);
return new PluginInstance<T>(
- context, listener, componentName, pluginFactory, instance);
+ context, listener, componentName, pluginFactory, null);
}
private boolean isPluginPackagePrivileged(String packageName) {
@@ -332,7 +338,9 @@
ClassLoader loader = mClassLoaderFactory.get();
Class<T> instanceClass = (Class<T>) Class.forName(
mComponentName.getClassName(), true, loader);
- return (T) mInstanceFactory.create(instanceClass);
+ T result = (T) mInstanceFactory.create(instanceClass);
+ Log.v(TAG, "Created plugin: " + result);
+ return result;
} catch (ClassNotFoundException ex) {
Log.e(TAG, "Failed to load plugin", ex);
} catch (IllegalAccessException ex) {
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index 0842953..78a5c98 100644
--- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -26,7 +26,7 @@
import android.view.View
import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.TITLE
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.TITLE
/** Displays security messages for the keyguard bouncer. */
open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a90a34c..360f755 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,8 +1,14 @@
package com.android.keyguard;
import static android.view.View.ALPHA;
+import static android.view.View.SCALE_X;
+import static android.view.View.SCALE_Y;
import static android.view.View.TRANSLATION_Y;
+import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_X_CLOCK_DESIGN;
+import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_DESIGN;
+import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_SIZE;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -17,6 +23,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import androidx.core.content.res.ResourcesCompat;
import com.android.app.animation.Interpolators;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
@@ -44,6 +51,7 @@
private static final long STATUS_AREA_START_DELAY_MILLIS = 0;
private static final long STATUS_AREA_MOVE_UP_MILLIS = 967;
private static final long STATUS_AREA_MOVE_DOWN_MILLIS = 467;
+ private static final float SMARTSPACE_TRANSLATION_CENTER_MULTIPLIER = 1.4f;
@IntDef({LARGE, SMALL})
@Retention(RetentionPolicy.SOURCE)
@@ -88,14 +96,18 @@
private KeyguardClockFrame mLargeClockFrame;
private ClockController mClock;
- private View mStatusArea;
+ private KeyguardStatusAreaView mStatusArea;
private int mSmartspaceTopOffset;
+ private float mWeatherClockSmartspaceScaling = 1f;
+ private int mWeatherClockSmartspaceTranslateX = 0;
+ private int mWeatherClockSmartspaceTranslateY = 0;
private int mDrawAlpha = 255;
/**
* Maintain state so that a newly connected plugin can be initialized.
*/
private float mDarkAmount;
+ private boolean mSplitShadeCentered = false;
/**
* Indicates which clock is currently displayed - should be one of {@link ClockSize}.
@@ -105,7 +117,7 @@
@VisibleForTesting AnimatorSet mClockInAnim = null;
@VisibleForTesting AnimatorSet mClockOutAnim = null;
- private AnimatorSet mStatusAreaAnim = null;
+ @VisibleForTesting AnimatorSet mStatusAreaAnim = null;
private int mClockSwitchYAmount;
@VisibleForTesting boolean mChildrenAreLaidOut = false;
@@ -117,13 +129,30 @@
}
/**
- * Apply dp changes on font/scale change
+ * Apply dp changes on configuration change
*/
- public void onDensityOrFontScaleChanged() {
+ public void onConfigChanged() {
mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_clock_switch_y_shift);
mSmartspaceTopOffset = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_smartspace_top_offset);
+ mWeatherClockSmartspaceScaling = ResourcesCompat.getFloat(
+ mContext.getResources(), R.dimen.weather_clock_smartspace_scale);
+ mWeatherClockSmartspaceTranslateX = mContext.getResources().getDimensionPixelSize(
+ R.dimen.weather_clock_smartspace_translateX);
+ mWeatherClockSmartspaceTranslateY = mContext.getResources().getDimensionPixelSize(
+ R.dimen.weather_clock_smartspace_translateY);
+ updateStatusArea(/* animate= */false);
+ }
+
+ /**
+ * Enable or disable split shade specific positioning
+ */
+ public void setSplitShadeCentered(boolean splitShadeCentered) {
+ if (mSplitShadeCentered != splitShadeCentered) {
+ mSplitShadeCentered = splitShadeCentered;
+ updateStatusArea(/* animate= */true);
+ }
}
@Override
@@ -134,7 +163,7 @@
mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
mStatusArea = findViewById(R.id.keyguard_status_area);
- onDensityOrFontScaleChanged();
+ onConfigChanged();
}
@Override
@@ -182,6 +211,13 @@
mSmallClockFrame.addView(clock.getSmallClock().getView());
mLargeClockFrame.addView(clock.getLargeClock().getView());
updateClockTargetRegions();
+ updateStatusArea(/* animate= */false);
+ }
+
+ private void updateStatusArea(boolean animate) {
+ if (mDisplayedClockSize != null && mChildrenAreLaidOut) {
+ updateClockViews(mDisplayedClockSize == LARGE, animate);
+ }
}
void updateClockTargetRegions() {
@@ -230,13 +266,25 @@
mStatusAreaAnim = null;
View in, out;
- float statusAreaYTranslation, clockInYTranslation, clockOutYTranslation;
+ float statusAreaYTranslation, statusAreaClockScale = 1f;
+ float statusAreaClockTranslateX = 0f, statusAreaClockTranslateY = 0f;
+ float clockInYTranslation, clockOutYTranslation;
if (useLargeClock) {
out = mSmallClockFrame;
in = mLargeClockFrame;
if (indexOfChild(in) == -1) addView(in, 0);
statusAreaYTranslation = mSmallClockFrame.getTop() - mStatusArea.getTop()
+ mSmartspaceTopOffset;
+ // TODO: Load from clock config when less risky
+ if (mClock != null
+ && mClock.getLargeClock().getConfig().getHasCustomWeatherDataDisplay()) {
+ statusAreaClockScale = mWeatherClockSmartspaceScaling;
+ statusAreaClockTranslateX = mWeatherClockSmartspaceTranslateX;
+ statusAreaClockTranslateY = mWeatherClockSmartspaceTranslateY;
+ if (mSplitShadeCentered) {
+ statusAreaClockTranslateX *= SMARTSPACE_TRANSLATION_CENTER_MULTIPLIER;
+ }
+ }
clockInYTranslation = 0;
clockOutYTranslation = 0; // Small clock translation is handled with statusArea
} else {
@@ -259,7 +307,12 @@
in.setAlpha(1f);
in.setTranslationY(clockInYTranslation);
in.setVisibility(VISIBLE);
- mStatusArea.setTranslationY(statusAreaYTranslation);
+ mStatusArea.setScaleX(statusAreaClockScale);
+ mStatusArea.setScaleY(statusAreaClockScale);
+ mStatusArea.setTranslateXFromClockDesign(statusAreaClockTranslateX);
+ mStatusArea.setTranslateYFromClockDesign(statusAreaClockTranslateY);
+ mStatusArea.setTranslateYFromClockSize(statusAreaYTranslation);
+ mSmallClockFrame.setTranslationY(statusAreaYTranslation);
return;
}
@@ -301,8 +354,15 @@
useLargeClock ? STATUS_AREA_MOVE_UP_MILLIS : STATUS_AREA_MOVE_DOWN_MILLIS);
mStatusAreaAnim.setInterpolator(Interpolators.EMPHASIZED);
mStatusAreaAnim.playTogether(
- ObjectAnimator.ofFloat(mStatusArea, TRANSLATION_Y, statusAreaYTranslation),
- ObjectAnimator.ofFloat(mSmallClockFrame, TRANSLATION_Y, statusAreaYTranslation));
+ ObjectAnimator.ofFloat(mStatusArea, TRANSLATE_Y_CLOCK_SIZE.getProperty(),
+ statusAreaYTranslation),
+ ObjectAnimator.ofFloat(mSmallClockFrame, TRANSLATION_Y, statusAreaYTranslation),
+ ObjectAnimator.ofFloat(mStatusArea, SCALE_X, statusAreaClockScale),
+ ObjectAnimator.ofFloat(mStatusArea, SCALE_Y, statusAreaClockScale),
+ ObjectAnimator.ofFloat(mStatusArea, TRANSLATE_X_CLOCK_DESIGN.getProperty(),
+ statusAreaClockTranslateX),
+ ObjectAnimator.ofFloat(mStatusArea, TRANSLATE_Y_CLOCK_DESIGN.getProperty(),
+ statusAreaClockTranslateY));
mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
if (mStatusAreaAnim == animation) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index de93f1b..84fc720f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -330,10 +330,10 @@
}
/**
- * Apply dp changes on font/scale change
+ * Apply dp changes on configuration change
*/
- public void onDensityOrFontScaleChanged() {
- mView.onDensityOrFontScaleChanged();
+ public void onConfigChanged() {
+ mView.onConfigChanged();
mKeyguardSmallClockTopMargin =
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
mKeyguardLargeClockTopMargin =
@@ -344,6 +344,12 @@
setDateWeatherVisibility();
}
+ /**
+ * Enable or disable split shade center specific positioning
+ */
+ public void setSplitShadeCentered(boolean splitShadeCentered) {
+ mView.setSplitShadeCentered(splitShadeCentered);
+ }
/**
* Set which clock should be displayed on the keyguard. The other one will be automatically
@@ -407,7 +413,7 @@
scale, props, animate);
if (mStatusArea != null) {
- PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
+ PropertyAnimator.setProperty(mStatusArea, KeyguardStatusAreaView.TRANSLATE_X_AOD,
x, props, animate);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index b0a5d7c..20e4656 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -34,9 +34,9 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.keyguard.bouncer.ui.BouncerMessageView;
-import com.android.systemui.keyguard.ui.binder.BouncerMessageViewBinder;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.ui.BouncerMessageView;
+import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder;
import com.android.systemui.log.BouncerLogger;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.ViewController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 0332c9f..363dd01 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -208,7 +208,7 @@
@Override
public void run() {
final View host = mHost.get();
- if (host != null) {
+ if (host != null && host.isVisibleToUser()) {
host.announceForAccessibility(mTextToAnnounce);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 57df33e..7c511a3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -74,7 +74,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -275,13 +275,6 @@
*/
@Override
public void finish(boolean fromPrimaryAuth, int targetUserId) {
- if (!mKeyguardStateController.canDismissLockScreen() && !fromPrimaryAuth) {
- Log.e(TAG,
- "Tried to dismiss keyguard when lockscreen is not dismissible and user "
- + "was not authenticated with a primary security method "
- + "(pin/password/pattern).");
- return;
- }
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt
index 1461dbe..7c8d91f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt
@@ -22,7 +22,7 @@
import androidx.core.graphics.drawable.DrawableCompat
import com.android.settingslib.Utils
import com.android.systemui.R
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.EMERGENCY_BUTTON
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.EMERGENCY_BUTTON
abstract class KeyguardSimInputView(context: Context, attrs: AttributeSet) :
KeyguardPinBasedInputView(context, attrs) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusAreaView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusAreaView.kt
new file mode 100644
index 0000000..e7da2b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusAreaView.kt
@@ -0,0 +1,118 @@
+package com.android.keyguard
+
+import android.content.Context
+import android.util.AttributeSet
+import android.util.FloatProperty
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.notification.AnimatableProperty
+
+class KeyguardStatusAreaView(
+ context: Context,
+ attrs: AttributeSet? = null,
+) : LinearLayout(context, attrs) {
+ var translateXFromClockDesign = 0f
+ get() = field
+ set(value) {
+ field = value
+ translationX = translateXFromAod + translateXFromClockDesign + translateXFromUnfold
+ }
+
+ var translateXFromAod = 0f
+ get() = field
+ set(value) {
+ field = value
+ translationX = translateXFromAod + translateXFromClockDesign + translateXFromUnfold
+ }
+
+ var translateXFromUnfold = 0F
+ get() = field
+ set(value) {
+ field = value
+ translationX = translateXFromAod + translateXFromClockDesign + translateXFromUnfold
+ }
+
+ var translateYFromClockSize = 0f
+ get() = field
+ set(value) {
+ field = value
+ translationY = value + translateYFromClockDesign
+ }
+
+ var translateYFromClockDesign = 0f
+ get() = field
+ set(value) {
+ field = value
+ translationY = value + translateYFromClockSize
+ }
+
+ companion object {
+ @JvmField
+ val TRANSLATE_X_CLOCK_DESIGN =
+ AnimatableProperty.from(
+ object : FloatProperty<KeyguardStatusAreaView>("TranslateXClockDesign") {
+ override fun setValue(view: KeyguardStatusAreaView, value: Float) {
+ view.translateXFromClockDesign = value
+ }
+
+ override fun get(view: KeyguardStatusAreaView): Float {
+ return view.translateXFromClockDesign
+ }
+ },
+ R.id.translate_x_clock_design_animator_tag,
+ R.id.translate_x_clock_design_animator_start_tag,
+ R.id.translate_x_clock_design_animator_end_tag
+ )
+
+ @JvmField
+ val TRANSLATE_X_AOD =
+ AnimatableProperty.from(
+ object : FloatProperty<KeyguardStatusAreaView>("TranslateXAod") {
+ override fun setValue(view: KeyguardStatusAreaView, value: Float) {
+ view.translateXFromAod = value
+ }
+
+ override fun get(view: KeyguardStatusAreaView): Float {
+ return view.translateXFromAod
+ }
+ },
+ R.id.translate_x_aod_animator_tag,
+ R.id.translate_x_aod_animator_start_tag,
+ R.id.translate_x_aod_animator_end_tag
+ )
+
+ @JvmField
+ val TRANSLATE_Y_CLOCK_SIZE =
+ AnimatableProperty.from(
+ object : FloatProperty<KeyguardStatusAreaView>("TranslateYClockSize") {
+ override fun setValue(view: KeyguardStatusAreaView, value: Float) {
+ view.translateYFromClockSize = value
+ }
+
+ override fun get(view: KeyguardStatusAreaView): Float {
+ return view.translateYFromClockSize
+ }
+ },
+ R.id.translate_y_clock_size_animator_tag,
+ R.id.translate_y_clock_size_animator_start_tag,
+ R.id.translate_y_clock_size_animator_end_tag
+ )
+
+ @JvmField
+ val TRANSLATE_Y_CLOCK_DESIGN =
+ AnimatableProperty.from(
+ object : FloatProperty<KeyguardStatusAreaView>("TranslateYClockDesign") {
+ override fun setValue(view: KeyguardStatusAreaView, value: Float) {
+ view.translateYFromClockDesign = value
+ }
+
+ override fun get(view: KeyguardStatusAreaView): Float {
+ return view.translateYFromClockDesign
+ }
+ },
+ R.id.translate_y_clock_design_animator_tag,
+ R.id.translate_y_clock_design_animator_start_tag,
+ R.id.translate_y_clock_design_animator_end_tag
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 835cc13..00500d6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -24,6 +24,7 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.transition.ChangeBounds;
import android.transition.Transition;
@@ -280,8 +281,8 @@
}
@Override
- public void onDensityOrFontScaleChanged() {
- mKeyguardClockSwitchController.onDensityOrFontScaleChanged();
+ public void onConfigChanged(Configuration newConfig) {
+ mKeyguardClockSwitchController.onConfigChanged();
}
};
@@ -329,6 +330,7 @@
boolean splitShadeEnabled,
boolean shouldBeCentered,
boolean animate) {
+ mKeyguardClockSwitchController.setSplitShadeCentered(splitShadeEnabled && shouldBeCentered);
if (mStatusViewCentered == shouldBeCentered) {
return;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index edd150c..ca64ae0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -53,7 +53,10 @@
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
setOf(
- ViewIdToTranslate(R.id.keyguard_status_area, START, filterKeyguard),
+ ViewIdToTranslate(R.id.keyguard_status_area, START, filterKeyguard,
+ { view, value ->
+ (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
+ }),
ViewIdToTranslate(
R.id.lockscreen_clock_view_large, START, filterKeyguardAndSplitShadeOnly),
ViewIdToTranslate(R.id.lockscreen_clock_view, START, filterKeyguard),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 430c5e1..64ab758 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -155,6 +155,8 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpsysTableLogger;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent;
@@ -380,6 +382,7 @@
private final ActiveUnlockConfig mActiveUnlockConfig;
private final IDreamManager mDreamManager;
private final TelephonyManager mTelephonyManager;
+ private final FeatureFlags mFeatureFlags;
@Nullable
private final FingerprintManager mFpm;
@Nullable
@@ -2290,7 +2293,8 @@
@Nullable BiometricManager biometricManager,
FaceWakeUpTriggersConfig faceWakeUpTriggersConfig,
DevicePostureController devicePostureController,
- Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider) {
+ Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider,
+ FeatureFlags featureFlags) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2322,6 +2326,7 @@
mPackageManager = packageManager;
mFpm = fingerprintManager;
mFaceManager = faceManager;
+ mFeatureFlags = featureFlags;
mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
mFaceAcquiredInfoIgnoreList = Arrays.stream(
mContext.getResources().getIntArray(
@@ -3013,7 +3018,12 @@
|| shouldListenForFingerprintAssistant
|| (mKeyguardOccluded && mIsDreaming)
|| (mKeyguardOccluded && userDoesNotHaveTrust && mKeyguardShowing
- && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing));
+ && (mOccludingAppRequestingFp
+ || isUdfps
+ || mAlternateBouncerShowing
+ || mFeatureFlags.isEnabled(Flags.FP_LISTEN_OCCLUDING_APPS)
+ )
+ );
// Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -3170,6 +3180,13 @@
|| (posture == mConfigFaceAuthSupportedPosture);
}
+ /**
+ * If the current device posture allows face auth to run.
+ */
+ public boolean doesCurrentPostureAllowFaceAuth() {
+ return doesPostureAllowFaceAuth(mPostureState);
+ }
+
private void logListenerModelData(@NonNull KeyguardListenModel model) {
mLogger.logKeyguardListenerModel(model);
if (model instanceof KeyguardFingerprintListenModel) {
@@ -3552,7 +3569,6 @@
*/
private void handleTimeUpdate() {
Assert.isMainThread();
- mLogger.d("handleTimeUpdate");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -3617,9 +3633,9 @@
private void handleBatteryUpdate(BatteryStatus status) {
Assert.isMainThread();
final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
- mLogger.logHandleBatteryUpdate(batteryUpdateInteresting);
mBatteryStatus = status;
if (batteryUpdateInteresting) {
+ mLogger.logHandleBatteryUpdate(mBatteryStatus);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -3656,7 +3672,8 @@
mLogger.logSimState(subId, slotId, state);
boolean becameAbsent = false;
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)
+ && state != TelephonyManager.SIM_STATE_UNKNOWN) {
mLogger.w("invalid subId in handleSimStateChange()");
/* Only handle No SIM(ABSENT) and Card Error(CARD_IO_ERROR) due to
* handleServiceStateChange() handle other case */
@@ -3691,7 +3708,7 @@
data.subId = subId;
data.slotId = slotId;
}
- if ((changed || becameAbsent) && state != TelephonyManager.SIM_STATE_UNKNOWN) {
+ if ((changed || becameAbsent) || state == TelephonyManager.SIM_STATE_UNKNOWN) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 7cedecc..239a0cc 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -326,7 +326,7 @@
}
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
- && mView.getContentDescription() != null) {
+ && mView.getContentDescription() != null && mView.isVisibleToUser()) {
mView.announceForAccessibility(mView.getContentDescription());
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index 7d76f12..a04a48d 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -16,11 +16,11 @@
package com.android.keyguard;
import static com.android.settingslib.Utils.getColorAttrDefaultColor;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND_PRESSED;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_PRESSED;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND_PRESSED;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_PRESSED;
import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset;
import android.animation.AnimatorSet;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index ebd234f..3f1741a6 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -15,8 +15,8 @@
*/
package com.android.keyguard;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
import android.content.Context;
import android.content.res.ColorStateList;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index e22fc30..edc298c 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,7 +15,7 @@
*/
package com.android.keyguard;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java
index 32f06dc..7c129b4 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java
@@ -16,7 +16,7 @@
package com.android.keyguard;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 4557b34..56c0953 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -16,7 +16,7 @@
package com.android.keyguard;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.PIN_SHAPES;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -30,6 +30,7 @@
import android.transition.TransitionValues;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -51,12 +52,30 @@
private int mPosition = 0;
private final PinShapeAdapter mPinShapeAdapter;
private ValueAnimator mValueAnimator = ValueAnimator.ofFloat(1f, 0f);
+ private Rect mFirstChildVisibleRect = new Rect();
public PinShapeNonHintingView(Context context, AttributeSet attrs) {
super(context, attrs);
mPinShapeAdapter = new PinShapeAdapter(context);
}
@Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (getChildCount() > 0) {
+ View firstChild = getChildAt(0);
+ boolean isVisible = firstChild.getLocalVisibleRect(mFirstChildVisibleRect);
+ boolean clipped = mFirstChildVisibleRect.left > 0
+ || mFirstChildVisibleRect.right < firstChild.getWidth();
+ if (!isVisible || clipped) {
+ setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
+ return;
+ }
+ }
+
+ setGravity(Gravity.CENTER);
+ }
+
+ @Override
public void append() {
int size = getResources().getDimensionPixelSize(R.dimen.password_shape_size);
ImageView pinDot = new ImageView(getContext());
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 154b0ed..b57c2b5 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -20,7 +20,7 @@
import com.android.keyguard.KeyguardSecurityContainerController;
import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import dagger.BindsInstance;
import dagger.Subcomponent;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index 38f252a..893239b 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -28,7 +28,7 @@
import com.android.systemui.R;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 4c4b74d..1b1a3e9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -30,7 +30,7 @@
import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
-import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
+import com.android.settingslib.fuelgauge.BatteryStatus
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogLevel.DEBUG
@@ -38,6 +38,7 @@
import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.LogLevel.VERBOSE
import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
@@ -683,8 +684,27 @@
)
}
- fun logHandleBatteryUpdate(isInteresting: Boolean) {
- logBuffer.log(TAG, DEBUG, { bool1 = isInteresting }, { "handleBatteryUpdate: $bool1" })
+ fun logHandleBatteryUpdate(batteryStatus: BatteryStatus?) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = batteryStatus != null
+ int1 = batteryStatus?.status ?: -1
+ int2 = batteryStatus?.chargingStatus ?: -1
+ long1 = (batteryStatus?.level ?: -1).toLong()
+ long2 = (batteryStatus?.maxChargingWattage ?: -1).toLong()
+ str1 = "${batteryStatus?.plugged ?: -1}"
+ },
+ {
+ "handleBatteryUpdate: isNotNull: $bool1 " +
+ "BatteryStatus{status= $int1, " +
+ "level=$long1, " +
+ "plugged=$str1, " +
+ "chargingStatus=$int2, " +
+ "maxChargingWattage= $long2}"
+ }
+ )
}
fun scheduleWatchdog(@CompileTimeConstant watchdogType: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 39d9714..6ea0fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -80,7 +80,7 @@
@Override
public void start() {
- registerForBroadcasts(mEnabled);
+ updateEnabled();
}
private void fakeWakeAndUnlock(BiometricSourceType type) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt b/packages/SystemUI/src/com/android/systemui/PhoneSystemUIAppComponentFactory.kt
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
copy to packages/SystemUI/src/com/android/systemui/PhoneSystemUIAppComponentFactory.kt
index 390c54e..f06cb41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/PhoneSystemUIAppComponentFactory.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
@@ -14,13 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.data
+package com.android.systemui
-import dagger.Binds
-import dagger.Module
+import android.content.Context
-@Module
-interface BouncerViewModule {
- /** Binds BouncerView to BouncerViewImpl and makes it injectable. */
- @Binds fun bindBouncerView(bouncerViewImpl: BouncerViewImpl): BouncerView
+class PhoneSystemUIAppComponentFactory : SystemUIAppComponentFactoryBase() {
+ override fun createSystemUIInitializer(context: Context) = SystemUIInitializerImpl(context)
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8af92ce..3ca74ac 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -34,6 +34,7 @@
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.Log;
import android.view.MotionEvent;
@@ -80,9 +81,6 @@
protected final Handler mHandler;
- private float mMinSwipeProgress = 0f;
- private float mMaxSwipeProgress = 1f;
-
private final SpringConfig mSnapBackSpringConfig =
new SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
@@ -226,18 +224,11 @@
return v.getMeasuredWidth();
}
- public void setMinSwipeProgress(float minSwipeProgress) {
- mMinSwipeProgress = minSwipeProgress;
- }
-
- public void setMaxSwipeProgress(float maxSwipeProgress) {
- mMaxSwipeProgress = maxSwipeProgress;
- }
-
private float getSwipeProgressForOffset(View view, float translation) {
+ if (translation == 0) return 0;
float viewSize = getSize(view);
float result = Math.abs(translation / viewSize);
- return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
+ return Math.min(Math.max(0, result), 1);
}
/**
@@ -277,9 +268,11 @@
// invalidate the view's own bounds all the way up the view hierarchy
public static void invalidateGlobalRegion(View view) {
+ Trace.beginSection("SwipeHelper.invalidateGlobalRegion");
invalidateGlobalRegion(
view,
new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+ Trace.endSection();
}
// invalidate a rectangle relative to the view's coordinate system all the way up the view
@@ -492,7 +485,7 @@
}
if (!mCancelled || wasRemoved) {
mCallback.onChildDismissed(animView);
- resetSwipeOfView(animView);
+ resetViewIfSwiping(animView);
}
if (endAction != null) {
endAction.accept(mCancelled);
@@ -547,7 +540,7 @@
if (!cancelled) {
updateSwipeProgressFromOffset(animView, canBeDismissed);
- resetSwipeOfView(animView);
+ resetViewIfSwiping(animView);
// Clear the snapped view after success, assuming it's not being swiped now
if (animView == mTouchedView && !mIsSwiping) {
mTouchedView = null;
@@ -811,7 +804,7 @@
return mIsSwiping ? mTouchedView : null;
}
- protected void resetSwipeOfView(View view) {
+ protected void resetViewIfSwiping(View view) {
if (getSwipedView() == view) {
resetSwipeState();
}
@@ -825,6 +818,12 @@
resetSwipeStates(/* resetAll= */ true);
}
+ public void forceResetSwipeState(@NonNull View view) {
+ if (view.getTranslationX() == 0) return;
+ setTranslation(view, 0);
+ updateSwipeProgressFromOffset(view, /* dismissable= */ true, 0);
+ }
+
/** This method resets the swipe state, and if `resetAll` is true, also resets the snap state */
private void resetSwipeStates(boolean resetAll) {
final View touchedView = mTouchedView;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
deleted file mode 100644
index 527ce12..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.content.Context;
-
-/**
- * Starts up SystemUI using the AOSP {@link SystemUIInitializerImpl}.
- *
- * This initializer relies on reflection to start everything up and should be considered deprecated.
- * Instead, create your own {@link SystemUIAppComponentFactoryBase}, specify it in your
- * AndroidManifest.xml and construct your own {@link SystemUIInitializer} directly.
- *
- * @deprecated Define your own SystemUIAppComponentFactoryBase implementation and use that. This
- * implementation may be changed or removed in future releases.
- */
-@Deprecated
-public class SystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase {
- @Override
- protected SystemUIInitializer createSystemUIInitializer(Context context) {
- return SystemUIInitializerFactory.createWithContext(context);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 5505267..522b397 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -54,7 +54,7 @@
* Application class for SystemUI.
*/
public class SystemUIApplication extends Application implements
- SystemUIAppComponentFactory.ContextInitializer {
+ SystemUIAppComponentFactoryBase.ContextInitializer {
public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
@@ -66,7 +66,7 @@
*/
private CoreStartable[] mServices;
private boolean mServicesStarted;
- private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
+ private SystemUIAppComponentFactoryBase.ContextAvailableCallback mContextAvailableCallback;
private SysUIComponent mSysUIComponent;
private SystemUIInitializer mInitializer;
@@ -366,7 +366,7 @@
@Override
public void setContextAvailableCallback(
- SystemUIAppComponentFactory.ContextAvailableCallback callback) {
+ SystemUIAppComponentFactoryBase.ContextAvailableCallback callback) {
mContextAvailableCallback = callback;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
deleted file mode 100644
index b9454e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
+++ /dev/null
@@ -1,72 +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.systemui
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.util.Log
-import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.util.Assert
-
-/**
- * Factory to reflectively lookup a [SystemUIInitializer] to start SystemUI with.
- */
-@Deprecated("Provide your own {@link SystemUIAppComponentFactoryBase} that doesn't need this.")
-object SystemUIInitializerFactory {
- private const val TAG = "SysUIInitializerFactory"
- @SuppressLint("StaticFieldLeak")
- private var initializer: SystemUIInitializer? = null
-
- /**
- * Instantiate a [SystemUIInitializer] reflectively.
- */
- @JvmStatic
- fun createWithContext(context: Context): SystemUIInitializer {
- return createFromConfig(context)
- }
-
- /**
- * Instantiate a [SystemUIInitializer] reflectively.
- */
- @JvmStatic
- private fun createFromConfig(context: Context): SystemUIInitializer {
- Assert.isMainThread()
-
- return createFromConfigNoAssert(context)
- }
-
- @JvmStatic
- @VisibleForTesting
- fun createFromConfigNoAssert(context: Context): SystemUIInitializer {
-
- return initializer ?: run {
- val className = context.getString(R.string.config_systemUIFactoryComponent)
- if (className.isEmpty()) {
- throw RuntimeException("No SystemUIFactory component configured")
- }
- try {
- val cls = context.classLoader.loadClass(className)
- val constructor = cls.getConstructor(Context::class.java)
- (constructor.newInstance(context) as SystemUIInitializer).apply {
- initializer = this
- }
- } catch (t: Throwable) {
- Log.w(TAG, "Error creating SystemUIInitializer component: $className", t)
- throw t
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index ba3c860..6cf9eff 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -82,11 +82,8 @@
mLogBufferFreezer.attach(mBroadcastDispatcher);
// Attempt to dump all LogBuffers for any uncaught exception
- mUncaughtExceptionPreHandlerManager.registerHandler((thread, throwable) -> {
- if (throwable instanceof Exception) {
- mLogBufferEulogizer.record(((Exception) throwable));
- }
- });
+ mUncaughtExceptionPreHandlerManager.registerHandler(
+ (thread, throwable) -> mLogBufferEulogizer.record(throwable));
// If configured, set up a battery notification
if (getResources().getBoolean(R.bool.config_showNotificationForUnknownBatteryState)) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index eebc1f0..2f6a68c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -329,7 +329,9 @@
// binder calls
final Optional<CentralSurfaces> centralSurfacesOptional =
mCentralSurfacesOptionalLazy.get();
- if (centralSurfacesOptional.map(CentralSurfaces::isPanelExpanded).orElse(false)
+ if (centralSurfacesOptional.isPresent()
+ && centralSurfacesOptional.get().getShadeViewController() != null
+ && centralSurfacesOptional.get().getShadeViewController().isPanelExpanded()
&& !centralSurfacesOptional.get().isKeyguardShowing()) {
if (!mDismissNotificationShadeActionRegistered) {
mA11yManager.registerSystemAction(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index b086912..31b0f056 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -18,7 +18,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -405,16 +404,23 @@
}
private int getMagnificationMode() {
+ // If current capability is window mode, we would like the default value of the mode to
+ // be WINDOW, otherwise, the default value would be FULLSCREEN.
+ int defaultValue =
+ (getMagnificationCapability() == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)
+ ? ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
+ : ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+
return mSecureSettings.getIntForUser(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
- ACCESSIBILITY_MAGNIFICATION_MODE_NONE,
+ defaultValue,
UserHandle.USER_CURRENT);
}
private int getMagnificationCapability() {
return mSecureSettings.getIntForUser(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
- ACCESSIBILITY_MAGNIFICATION_MODE_NONE,
+ ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
UserHandle.USER_CURRENT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 665a398..2b83e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -105,6 +105,8 @@
AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
public static final int INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS =
AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS;
+ public static final int INVOCATION_TYPE_NAV_HANDLE_LONG_PRESS =
+ AssistUtils.INVOCATION_TYPE_NAV_HANDLE_LONG_PRESS;
public static final int DISMISS_REASON_INVOCATION_CANCELLED = 1;
public static final int DISMISS_REASON_TAP = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index b2ffea3..e58876a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -242,15 +242,17 @@
}
private boolean isOwnerInForeground() {
- final String clientPackage = mCurrentDialog.getOpPackageName();
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(clientPackage)
- && !Utils.isSystem(mContext, clientPackage)) {
- Log.w(TAG, "Evicting client due to: " + topPackage);
- return false;
+ if (mCurrentDialog != null) {
+ final String clientPackage = mCurrentDialog.getOpPackageName();
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(clientPackage)
+ && !Utils.isSystem(mContext, clientPackage)) {
+ Log.w(TAG, "Evicting client due to: " + topPackage);
+ return false;
+ }
}
}
return true;
@@ -1054,6 +1056,10 @@
return false;
}
+ private String getNotRecognizedString(@Modality int modality) {
+ return mContext.getString(modality == TYPE_FACE
+ ? R.string.biometric_face_not_recognized : R.string.biometric_not_recognized);
+ }
private String getErrorString(@Modality int modality, int error, int vendorCode) {
switch (modality) {
@@ -1100,7 +1106,7 @@
mCurrentDialog.animateToCredentialUI();
} else if (isSoftError) {
final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
- ? mContext.getString(R.string.biometric_not_recognized)
+ ? getNotRecognizedString(modality)
: getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
// The camera privacy error can return before the prompt initializes its state,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index baaa96e..9d0cde1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -35,6 +35,7 @@
import android.util.Log
import android.util.RotationUtils
import android.view.Display
+import android.view.DisplayInfo
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Surface
@@ -53,11 +54,12 @@
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.util.boundsOnScreen
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.traceSection
import java.io.PrintWriter
@@ -129,6 +131,8 @@
}
@VisibleForTesting var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT
+ private val displayInfo = DisplayInfo()
+
private val overlayViewParams =
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
@@ -214,6 +218,23 @@
for (requestSource in requests) {
pw.println(" $requestSource.name")
}
+
+ pw.println("overlayView:")
+ pw.println(" width=${overlayView?.width}")
+ pw.println(" height=${overlayView?.height}")
+ pw.println(" boundsOnScreen=${overlayView?.boundsOnScreen}")
+
+ pw.println("displayStateInteractor:")
+ pw.println(" isInRearDisplayMode=${displayStateInteractor?.isInRearDisplayMode?.value}")
+
+ pw.println("sensorProps:")
+ pw.println(" displayId=${displayInfo.uniqueId}")
+ pw.println(" sensorType=${sensorProps?.sensorType}")
+ pw.println(" location=${sensorProps?.getLocation(displayInfo.uniqueId)}")
+
+ pw.println("overlayOffsets=$overlayOffsets")
+ pw.println("isReverseDefaultRotation=$isReverseDefaultRotation")
+ pw.println("currentRotation=${displayInfo.rotation}")
}
private fun onOrientationChanged(@BiometricOverlayConstants.ShowReason reason: Int) {
@@ -226,6 +247,8 @@
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
overlayView = view
val display = context.display!!
+ // b/284098873 `context.display.rotation` may not up-to-date, we use displayInfo.rotation
+ display.getDisplayInfo(displayInfo)
val offsets =
sensorProps.getLocation(display.uniqueId).let { location ->
if (location == null) {
@@ -239,12 +262,12 @@
view.rotation =
display.asSideFpsAnimationRotation(
offsets.isYAligned(),
- getRotationFromDefault(display.rotation)
+ getRotationFromDefault(displayInfo.rotation)
)
lottie.setAnimation(
display.asSideFpsAnimation(
offsets.isYAligned(),
- getRotationFromDefault(display.rotation)
+ getRotationFromDefault(displayInfo.rotation)
)
)
lottie.addLottieOnCompositionLoadedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2eb5330..a91499a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -82,9 +82,9 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -173,6 +173,7 @@
@NonNull private final SecureSettings mSecureSettings;
@NonNull private final UdfpsUtils mUdfpsUtils;
@NonNull private final InputManager mInputManager;
+ @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
private final boolean mIgnoreRefreshRate;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
@@ -272,7 +273,8 @@
mUdfpsDisplayMode, mSecureSettings, requestId, reason, callback,
(view, event, fromUdfpsView) -> onTouch(requestId, event,
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
- mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsUtils)));
+ mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsUtils,
+ mUdfpsKeyguardAccessibilityDelegate)));
}
@Override
@@ -825,7 +827,8 @@
@NonNull SecureSettings secureSettings,
@NonNull InputManager inputManager,
@NonNull UdfpsUtils udfpsUtils,
- @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) {
+ @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
+ @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -871,6 +874,7 @@
mSecureSettings = secureSettings;
mUdfpsUtils = udfpsUtils;
mInputManager = inputManager;
+ mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
? singlePointerTouchProcessor : null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index cabe900..e542147 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -53,8 +53,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -103,7 +103,8 @@
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
- private val udfpsUtils: UdfpsUtils
+ private val udfpsUtils: UdfpsUtils,
+ private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
) {
/** The view, when [isShowing], or null. */
var overlayView: UdfpsView? = null
@@ -261,6 +262,7 @@
featureFlags,
primaryBouncerInteractor,
alternateBouncerInteractor,
+ udfpsKeyguardAccessibilityDelegate,
)
}
REASON_AUTH_BP -> {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt
new file mode 100644
index 0000000..fb7b56e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.biometrics
+
+import android.content.res.Resources
+import android.os.Bundle
+import android.view.View
+import android.view.accessibility.AccessibilityNodeInfo
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import javax.inject.Inject
+
+@SysUISingleton
+class UdfpsKeyguardAccessibilityDelegate
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val keyguardViewManager: StatusBarKeyguardViewManager,
+) : View.AccessibilityDelegate() {
+ override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo) {
+ super.onInitializeAccessibilityNodeInfo(host, info)
+ val clickAction =
+ AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+ resources.getString(R.string.accessibility_bouncer)
+ )
+ info.addAction(clickAction)
+ }
+
+ override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
+ // when an a11y service is enabled, double tapping on the fingerprint sensor should
+ // show the primary bouncer
+ return if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id) {
+ keyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
+ true
+ } else super.performAccessibilityAction(host, action, args)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 3fc3e82..9bafeec 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -20,6 +20,7 @@
import android.content.res.Configuration
import android.util.MathUtils
import android.view.MotionEvent
+import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -28,11 +29,11 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionListener
@@ -71,6 +72,7 @@
featureFlags: FeatureFlags,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
) :
UdfpsAnimationViewController<UdfpsKeyguardViewLegacy>(
view,
@@ -300,7 +302,10 @@
lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy = this
activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
view.mUseExpandedOverlay = useExpandedOverlay
- view.startIconAsyncInflate()
+ view.startIconAsyncInflate {
+ (view.findViewById(R.id.udfps_animation_view_internal) as View).accessibilityDelegate =
+ udfpsKeyguardAccessibilityDelegate
+ }
}
override fun onViewDetached() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
index a2840fc..b916810c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java
@@ -79,6 +79,7 @@
private float mInterpolatedDarkAmount;
private int mAnimationType = ANIMATION_NONE;
private boolean mFullyInflated;
+ private Runnable mOnFinishInflateRunnable;
public UdfpsKeyguardViewLegacy(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -90,7 +91,12 @@
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
}
- public void startIconAsyncInflate() {
+ /**
+ * Inflate internal udfps view on a background thread and call the onFinishRunnable
+ * when inflation is finished.
+ */
+ public void startIconAsyncInflate(Runnable onFinishInflate) {
+ mOnFinishInflateRunnable = onFinishInflate;
// inflate Lottie views on a background thread in case it takes a while to inflate
AsyncLayoutInflater inflater = new AsyncLayoutInflater(mContext);
inflater.inflate(R.layout.udfps_keyguard_view_internal, this,
@@ -103,6 +109,13 @@
}
@Override
+ void onSensorRectUpdated(RectF bounds) {
+ super.onSensorRectUpdated(bounds);
+ bounds.round(this.mSensorBounds);
+ postInvalidate();
+ }
+
+ @Override
void onDisplayConfiguring() {
}
@@ -323,6 +336,7 @@
frameInfo -> new PorterDuffColorFilter(mTextColorPrimary,
PorterDuff.Mode.SRC_ATOP)
);
+ mOnFinishInflateRunnable.run();
}
};
}
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 8486c3f..34c8d9f 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
@@ -339,7 +339,13 @@
launch {
delay(authState.delay)
- legacyCallback.onAction(Callback.ACTION_AUTHENTICATED)
+ legacyCallback.onAction(
+ if (authState.isAuthenticatedAndExplicitlyConfirmed) {
+ Callback.ACTION_AUTHENTICATED_AND_CONFIRMED
+ } else {
+ Callback.ACTION_AUTHENTICATED
+ }
+ )
}
}
}
@@ -512,9 +518,10 @@
}
applicationScope.launch {
- viewModel.showTemporaryHelp(
+ // help messages from the HAL should be displayed as temporary (i.e. soft) errors
+ viewModel.showTemporaryError(
help,
- messageAfterHelp = modalities.asDefaultHelpMessage(applicationContext),
+ messageAfterError = modalities.asDefaultHelpMessage(applicationContext),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 1dffa80..1a286cf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -28,6 +28,7 @@
import android.widget.TextView
import androidx.core.animation.addListener
import androidx.core.view.doOnLayout
+import androidx.core.view.isGone
import androidx.lifecycle.lifecycleScope
import com.android.systemui.R
import com.android.systemui.biometrics.AuthDialog
@@ -78,9 +79,11 @@
// cache the original position of the icon view (as done in legacy view)
// this must happen before any size changes can be made
- var iconHolderOriginalY = 0f
view.doOnLayout {
- iconHolderOriginalY = iconHolderView.y
+ // TODO(b/251476085): this old way of positioning has proven itself unreliable
+ // remove this and associated thing like (UdfpsDialogMeasureAdapter) and
+ // pin to the physical sensor
+ val iconHolderOriginalY = iconHolderView.y
// bind to prompt
// TODO(b/251476085): migrate the legacy panel controller and simplify this
@@ -141,7 +144,11 @@
listOf(
iconHolderView.asVerticalAnimator(
duration = duration.toLong(),
- toY = iconHolderOriginalY,
+ toY =
+ iconHolderOriginalY -
+ viewsToHideWhenSmall
+ .filter { it.isGone }
+ .sumOf { it.height },
),
viewsToFadeInOnSizeChange.asFadeInAnimator(
duration = duration.toLong(),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
index 9cb91b3..444082c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
@@ -29,10 +29,16 @@
val needsUserConfirmation: Boolean = false,
val delay: Long = 0,
) {
+ private var wasConfirmed = false
+
/** If authentication was successful and the user has confirmed (or does not need to). */
val isAuthenticatedAndConfirmed: Boolean
get() = isAuthenticated && !needsUserConfirmation
+ /** Same as [isAuthenticatedAndConfirmed] but only true if the user clicked a confirm button. */
+ val isAuthenticatedAndExplicitlyConfirmed: Boolean
+ get() = isAuthenticated && wasConfirmed
+
/** If a successful authentication has not occurred. */
val isNotAuthenticated: Boolean
get() = !isAuthenticated
@@ -45,12 +51,16 @@
val isAuthenticatedByFingerprint: Boolean
get() = isAuthenticated && authenticatedModality == BiometricModality.Fingerprint
- /** Copies this state, but toggles [needsUserConfirmation] to false. */
- fun asConfirmed(): PromptAuthState =
+ /**
+ * Copies this state, but toggles [needsUserConfirmation] to false and ensures that
+ * [isAuthenticatedAndExplicitlyConfirmed] is true.
+ */
+ fun asExplicitlyConfirmed(): PromptAuthState =
PromptAuthState(
- isAuthenticated = isAuthenticated,
- authenticatedModality = authenticatedModality,
- needsUserConfirmation = false,
- delay = delay,
- )
+ isAuthenticated = isAuthenticated,
+ authenticatedModality = authenticatedModality,
+ needsUserConfirmation = false,
+ delay = delay,
+ )
+ .apply { wasConfirmed = true }
}
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 2f8ed09..0fffee6 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
@@ -414,7 +414,7 @@
return
}
- _isAuthenticated.value = authState.asConfirmed()
+ _isAuthenticated.value = authState.asExplicitlyConfirmed()
_message.value = PromptMessage.Empty
_legacyState.value = AuthBiometricView.STATE_AUTHENTICATED
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactory.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
index 4085dab..3206c00 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.data.factory
+package com.android.systemui.bouncer.data.factory
import android.annotation.IntDef
import com.android.keyguard.KeyguardSecurityModel
@@ -73,9 +73,9 @@
import com.android.systemui.R.string.kg_wrong_password_try_again
import com.android.systemui.R.string.kg_wrong_pattern_try_again
import com.android.systemui.R.string.kg_wrong_pin_try_again
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.keyguard.bouncer.shared.model.Message
import javax.inject.Inject
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepository.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
index c4400bc..7e420cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.data.repository
+package com.android.systemui.bouncer.data.repository
import android.hardware.biometrics.BiometricSourceType
import android.hardware.biometrics.BiometricSourceType.FACE
@@ -33,11 +33,11 @@
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repo/BouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bouncer/data/repo/BouncerRepository.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
index 49a0a3c..ff896fa 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repo/BouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bouncer.data.repo
+package com.android.systemui.bouncer.data.repository
import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index 5d15e69..918e168 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -14,14 +14,14 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.data.repository
+package com.android.systemui.bouncer.data.repository
import android.os.Build
import android.util.Log
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.log.dagger.BouncerTableLog
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 148d425..2abdb84 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
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 a24a421..c833def 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
@@ -21,7 +21,7 @@
import com.android.systemui.R
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.bouncer.data.repo.BouncerRepository
+import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.domain.interactor.SceneInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
index 56f81fc..497747f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.os.Build
import android.util.Log
import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index 1754d93..d06dd8e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.os.CountDownTimer
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlin.math.roundToInt
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractor.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractor.kt
index 3099a49..5fbe99a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractor.kt
@@ -14,12 +14,12 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.view.View
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.util.ListenerSet
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 54bc349..c486603 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.content.Context
import android.content.res.ColorStateList
@@ -29,6 +29,11 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.DejankUtils
import com.android.systemui.R
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -36,24 +41,19 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.statusbar.policy.KeyguardStateController
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
-import javax.inject.Inject
/**
* Encapsulates business logic for interacting with the lock-screen primary (pin/pattern/password)
@@ -77,8 +77,8 @@
private val featureFlags: FeatureFlags,
@Application private val applicationScope: CoroutineScope,
) {
- private val passiveAuthBouncerDelay = context.resources.getInteger(
- R.integer.primary_bouncer_passive_auth_delay).toLong()
+ private val passiveAuthBouncerDelay =
+ context.resources.getInteger(R.integer.primary_bouncer_passive_auth_delay).toLong()
/** Runnable to show the primary bouncer. */
val showRunnable = Runnable {
repository.setPrimaryShow(true)
@@ -87,7 +87,7 @@
}
val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
- val isShowing: Flow<Boolean> = repository.primaryBouncerShow
+ val isShowing: StateFlow<Boolean> = repository.primaryBouncerShow
val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull()
@@ -384,20 +384,24 @@
mainHandler.removeCallbacks(showRunnable)
}
- private fun isBouncerShowing(): Boolean {
- return repository.primaryBouncerShow.value
+ /** Returns whether the primary bouncer is currently showing. */
+ fun isBouncerShowing(): Boolean {
+ return isShowing.value
}
/** Whether we want to wait to show the bouncer in case passive auth succeeds. */
private fun usePrimaryBouncerPassiveAuthDelay(): Boolean {
- val canRunFaceAuth = keyguardStateController.isFaceAuthEnabled &&
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE)
- val canRunActiveUnlock = currentUserActiveUnlockRunning &&
+ val canRunFaceAuth =
+ keyguardStateController.isFaceAuthEnabled &&
+ keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
+ keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()
+ val canRunActiveUnlock =
+ currentUserActiveUnlockRunning &&
keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()
return featureFlags.isEnabled(Flags.DELAY_BOUNCER) &&
- !needsFullscreenBouncer() &&
- (canRunFaceAuth || canRunActiveUnlock)
+ !needsFullscreenBouncer() &&
+ (canRunFaceAuth || canRunActiveUnlock)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
index c45faf0..9f17811 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
@@ -12,10 +12,9 @@
* WITHOUT WARRANTIES 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.constants
+package com.android.systemui.bouncer.shared.constants
object KeyguardBouncerConstants {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerCallbackActionsModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerCallbackActionsModel.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerCallbackActionsModel.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerCallbackActionsModel.kt
index 81cf5b4..afddd39 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerCallbackActionsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerCallbackActionsModel.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.shared.model
+package com.android.systemui.bouncer.shared.model
import com.android.systemui.plugins.ActivityStarter
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/shared/model/BouncerMessageModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/shared/model/BouncerMessageModel.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
index 46e8873..0e9e962 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/shared/model/BouncerMessageModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.shared.model
+package com.android.systemui.bouncer.shared.model
import android.content.res.ColorStateList
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerShowMessageModel.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerShowMessageModel.kt
index 05cdeaa..1878572 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerShowMessageModel.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.shared.model
+package com.android.systemui.bouncer.shared.model
import android.content.res.ColorStateList
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/keyguard/bouncer/ui/BouncerMessageView.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
index 4dc52ff..47fac2b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/bouncer/ui/BouncerMessageView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.ui
+package com.android.systemui.bouncer.ui
import android.content.Context
import android.util.AttributeSet
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerView.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerView.kt
index 871a3ff..dc00321 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerView.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.data
+package com.android.systemui.bouncer.ui
import android.view.KeyEvent
import android.window.OnBackAnimationCallback
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
index 390c54e..0cbfb68 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.data
+package com.android.systemui.bouncer.ui
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt
index 5b40dd7..5a59012 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/BouncerMessageViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.ui.binder
+package com.android.systemui.bouncer.ui.binder
import android.text.TextUtils
import android.util.PluralsMessageFormatter
@@ -23,11 +23,11 @@
import com.android.keyguard.BouncerKeyguardMessageArea
import com.android.keyguard.KeyguardMessageArea
import com.android.keyguard.KeyguardMessageAreaController
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.bouncer.shared.model.Message
+import com.android.systemui.bouncer.ui.BouncerMessageView
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
-import com.android.systemui.keyguard.bouncer.shared.model.Message
-import com.android.systemui.keyguard.bouncer.ui.BouncerMessageView
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.BouncerLogger
import kotlinx.coroutines.launch
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index dd1a9d2..34e934b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.ui.binder
+package com.android.systemui.bouncer.ui.binder
import android.view.KeyEvent
import android.view.View
@@ -28,11 +28,11 @@
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
+import com.android.systemui.bouncer.ui.BouncerViewDelegate
+import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
-import com.android.systemui.keyguard.data.BouncerViewDelegate
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.BouncerLogger
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
rename to packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 9602888..6ba8439 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -14,13 +14,13 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.bouncer.ui.viewmodel
import android.view.View
-import com.android.systemui.keyguard.data.BouncerView
-import com.android.systemui.keyguard.data.BouncerViewDelegate
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.bouncer.ui.BouncerViewDelegate
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 18bd467..ccbde01 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -312,6 +312,7 @@
Log.d(TAG, "Canceling loadSubscribtion")
it.invoke()
}
+ callback.error("Load cancelled")
}
override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt
index d7d1700..c921806 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.controller
interface ControlsTileResourceConfiguration {
+ fun getPackageName(): String?
fun getTileTitleId(): Int
fun getTileImageId(): Int
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt
index c96d3d4..0249060 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt
@@ -20,12 +20,14 @@
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
-/**
- * Default Instance for ControlsTileResourceConfiguration.
- */
+/** Default Instance for ControlsTileResourceConfiguration. */
@SysUISingleton
-class ControlsTileResourceConfigurationImpl @Inject constructor()
- : ControlsTileResourceConfiguration {
+class ControlsTileResourceConfigurationImpl @Inject constructor() :
+ ControlsTileResourceConfiguration {
+ override fun getPackageName(): String? {
+ return null
+ }
+
override fun getTileTitleId(): Int {
return R.string.quick_controls_title
}
@@ -33,4 +35,4 @@
override fun getTileImageId(): Int {
return R.drawable.controls_icon
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
index 7509a8a..94e5633 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
@@ -29,9 +29,9 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
-import kotlinx.coroutines.flow.StateFlow
import java.util.Optional
import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
/**
* Pseudo-component to inject into classes outside `com.android.systemui.controls`.
@@ -40,26 +40,26 @@
* instantiated if `featureEnabled` is true. Can also be queried for the availability of controls.
*/
@SysUISingleton
-class ControlsComponent @Inject constructor(
- @ControlsFeatureEnabled private val featureEnabled: Boolean,
- private val context: Context,
- private val lazyControlsController: Lazy<ControlsController>,
- private val lazyControlsUiController: Lazy<ControlsUiController>,
- private val lazyControlsListingController: Lazy<ControlsListingController>,
- private val lockPatternUtils: LockPatternUtils,
- private val keyguardStateController: KeyguardStateController,
- private val userTracker: UserTracker,
- controlsSettingsRepository: ControlsSettingsRepository,
- optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
+class ControlsComponent
+@Inject
+constructor(
+ @ControlsFeatureEnabled private val featureEnabled: Boolean,
+ private val context: Context,
+ private val lazyControlsController: Lazy<ControlsController>,
+ private val lazyControlsUiController: Lazy<ControlsUiController>,
+ private val lazyControlsListingController: Lazy<ControlsListingController>,
+ private val lockPatternUtils: LockPatternUtils,
+ private val keyguardStateController: KeyguardStateController,
+ private val userTracker: UserTracker,
+ controlsSettingsRepository: ControlsSettingsRepository,
+ optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
) {
val canShowWhileLockedSetting: StateFlow<Boolean> =
- controlsSettingsRepository.canShowControlsInLockscreen
+ controlsSettingsRepository.canShowControlsInLockscreen
private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
- optionalControlsTileResourceConfiguration.orElse(
- ControlsTileResourceConfigurationImpl()
- )
+ optionalControlsTileResourceConfiguration.orElse(ControlsTileResourceConfigurationImpl())
fun getControlsController(): Optional<ControlsController> {
return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
@@ -77,9 +77,7 @@
}
}
- /**
- * @return true if controls are feature-enabled and the user has the setting enabled
- */
+ /** @return true if controls are feature-enabled and the user has the setting enabled */
fun isEnabled() = featureEnabled
/**
@@ -90,8 +88,10 @@
*/
fun getVisibility(): Visibility {
if (!isEnabled()) return Visibility.UNAVAILABLE
- if (lockPatternUtils.getStrongAuthForUser(userTracker.userHandle.identifier)
- == STRONG_AUTH_REQUIRED_AFTER_BOOT) {
+ if (
+ lockPatternUtils.getStrongAuthForUser(userTracker.userHandle.identifier) ==
+ STRONG_AUTH_REQUIRED_AFTER_BOOT
+ ) {
return Visibility.AVAILABLE_AFTER_UNLOCK
}
if (!canShowWhileLockedSetting.value && !keyguardStateController.isUnlocked()) {
@@ -102,7 +102,13 @@
}
enum class Visibility {
- AVAILABLE, AVAILABLE_AFTER_UNLOCK, UNAVAILABLE
+ AVAILABLE,
+ AVAILABLE_AFTER_UNLOCK,
+ UNAVAILABLE
+ }
+
+ fun getPackageName(): String? {
+ return controlsTileResourceConfiguration.getPackageName()
}
fun getTileTitleId(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 8896519..9eb85df 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -52,7 +52,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.keyboard.KeyboardModule;
-import com.android.systemui.keyguard.data.BouncerViewModule;
+import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.log.dagger.MonitorLog;
import com.android.systemui.log.table.TableLogBuffer;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index b71871e..d70c57f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,12 +16,11 @@
package com.android.systemui.dagger;
-import android.content.Context;
import android.os.HandlerThread;
import androidx.annotation.Nullable;
-import com.android.systemui.SystemUIInitializerFactory;
+import com.android.systemui.SystemUIInitializer;
import com.android.systemui.tv.TvWMComponent;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
@@ -49,7 +48,7 @@
/**
* Dagger Subcomponent for WindowManager. This class explicitly describes the interfaces exported
* from the WM component into the SysUI component (in
- * {@link SystemUIInitializerFactory#init(Context, boolean)}), and references the specific dependencies
+ * {@link SystemUIInitializer#init(boolean)}), and references the specific dependencies
* provided by its particular device/form-factor SystemUI implementation.
*
* ie. {@link WMComponent} includes {@link WMShellModule}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c5e7e0d..ee046c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -34,13 +34,11 @@
import com.android.systemui.complication.ComplicationLayoutParams.Position
import com.android.systemui.dreams.dagger.DreamOverlayModule
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
-import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_ANIMATION_DURATION
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
-import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.flow.MutableStateFlow
@@ -129,6 +127,12 @@
)
}
}
+
+ launch {
+ transitionViewModel.transitionEnded.collect { _ ->
+ mOverlayStateController.setExitAnimationsRunning(false)
+ }
+ }
}
configController.removeCallback(configCallback)
@@ -251,9 +255,9 @@
}
/** Starts the dream content and dream overlay exit animations. */
- fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
+ fun wakeUp() {
cancelAnimations()
- executor.executeDelayed(doneCallback, DREAM_ANIMATION_DURATION.inWholeMilliseconds)
+ mOverlayStateController.setExitAnimationsRunning(true)
}
/** Cancels the dream content and dream overlay animations, if they're currently running. */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index c22019e..78ac453 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -31,8 +31,6 @@
import android.view.View;
import android.view.ViewGroup;
-import androidx.annotation.NonNull;
-
import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
@@ -41,12 +39,11 @@
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.Arrays;
@@ -302,20 +299,15 @@
/**
* Handle the dream waking up and run any necessary animations.
- *
- * @param onAnimationEnd Callback to trigger once animations are finished.
- * @param callbackExecutor Executor to execute the callback on.
*/
- public void wakeUp(@NonNull Runnable onAnimationEnd,
- @NonNull DelayableExecutor callbackExecutor) {
+ public void wakeUp() {
// When swiping causes wakeup, do not run any animations as the dream should exit as soon
// as possible.
if (mWakingUpFromSwipe) {
- onAnimationEnd.run();
return;
}
- mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
+ mDreamOverlayAnimationsController.wakeUp();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index df2a749..553405f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -116,6 +116,17 @@
}
};
+ private final DreamOverlayStateController.Callback mExitAnimationFinishedCallback =
+ new DreamOverlayStateController.Callback() {
+ @Override
+ public void onStateChanged() {
+ if (!mStateController.areExitAnimationsRunning()) {
+ mStateController.removeCallback(mExitAnimationFinishedCallback);
+ resetCurrentDreamOverlayLocked();
+ }
+ }
+ };
+
private final DreamOverlayStateController mStateController;
@VisibleForTesting
@@ -257,10 +268,10 @@
}
@Override
- public void onWakeUp(@NonNull Runnable onCompletedCallback) {
+ public void onWakeUp() {
if (mDreamOverlayContainerViewController != null) {
mDreamOverlayCallbackController.onWakeUp();
- mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
+ mDreamOverlayContainerViewController.wakeUp();
}
}
@@ -330,6 +341,11 @@
}
private void resetCurrentDreamOverlayLocked() {
+ if (mStateController.areExitAnimationsRunning()) {
+ mStateController.addCallback(mExitAnimationFinishedCallback);
+ return;
+ }
+
if (mStarted && mWindow != null) {
try {
mWindowManager.removeView(mWindow.getDecorView());
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 570132e1..1cd3774 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -35,9 +35,11 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dreams.touch.scrim.ScrimController;
import com.android.systemui.dreams.touch.scrim.ScrimManager;
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -76,6 +78,8 @@
private static final String TAG = "BouncerSwipeTouchHandler";
private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final LockPatternUtils mLockPatternUtils;
+ private final UserTracker mUserTracker;
private final float mBouncerZoneScreenPercentage;
private final ScrimManager mScrimManager;
@@ -151,6 +155,11 @@
return true;
}
+ // Don't set expansion if the user doesn't have a pin/password set.
+ if (!mLockPatternUtils.isSecure(mUserTracker.getUserId())) {
+ return true;
+ }
+
// For consistency, we adopt the expansion definition found in the
// PanelViewController. In this case, expansion refers to the view above the
// bouncer. As that view's expansion shrinks, the bouncer appears. The bouncer
@@ -204,6 +213,8 @@
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
VelocityTrackerFactory velocityTrackerFactory,
+ LockPatternUtils lockPatternUtils,
+ UserTracker userTracker,
@Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING)
FlingAnimationUtils flingAnimationUtils,
@Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
@@ -213,6 +224,8 @@
mCentralSurfaces = centralSurfaces;
mScrimManager = scrimManager;
mNotificationShadeWindowController = notificationShadeWindowController;
+ mLockPatternUtils = lockPatternUtils;
+ mUserTracker = userTracker;
mBouncerZoneScreenPercentage = swipeRegionPercentage;
mFlingAnimationUtils = flingAnimationUtils;
mFlingAnimationUtilsClosing = flingAnimationUtilsClosing;
@@ -347,6 +360,11 @@
return;
}
+ // Don't set expansion if the user doesn't have a pin/password set.
+ if (!mLockPatternUtils.isSecure(mUserTracker.getUserId())) {
+ return;
+ }
+
// The animation utils deal in pixel units, rather than expansion height.
final float viewHeight = mTouchSession.getBounds().height();
final float currentHeight = viewHeight * mCurrentExpansion;
diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
index 25b90be..bd43302 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
@@ -72,7 +72,7 @@
* The file will be prefaced by the [reason], which will then be returned (presumably so it can
* be thrown).
*/
- fun <T : Exception> record(reason: T): T {
+ fun <T : Throwable> record(reason: T): T {
val start = systemClock.uptimeMillis()
var duration = 0L
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index cc904b2e..c503846 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -247,7 +247,7 @@
/** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */
// TODO(b/279794160): Tracking bug.
@JvmField
- val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer")
+ val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer", teamfood = true)
/** Migrate the indication area to the new keyguard root view. */
// TODO(b/280067944): Tracking bug.
@@ -259,6 +259,11 @@
@JvmField
val FP_LISTEN_OCCLUDING_APPS = unreleasedFlag(237, "fp_listen_occluding_apps")
+ /** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
+ // TODO(b/286563884): Tracking bug
+ @JvmField
+ val KEYGUARD_TALKBACK_FIX = unreleasedFlag(238, "keyguard_talkback_fix")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -355,8 +360,7 @@
// TODO(b/280426085): Tracking Bug
@JvmField
- val NEW_BLUETOOTH_REPOSITORY =
- unreleasedFlag(612, "new_bluetooth_repository", teamfood = true)
+ val NEW_BLUETOOTH_REPOSITORY = releasedFlag(612, "new_bluetooth_repository")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
@@ -438,9 +442,6 @@
// TODO(b/254512758): Tracking Bug
@JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
- // TODO(b/265045965): Tracking Bug
- val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
-
// TODO(b/273509374): Tracking Bug
@JvmField
val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = releasedFlag(1006,
@@ -598,7 +599,7 @@
// 1300 - screenshots
// TODO(b/264916608): Tracking Bug
- @JvmField val SCREENSHOT_METADATA = unreleasedFlag(1302, "screenshot_metadata", teamfood = true)
+ @JvmField val SCREENSHOT_METADATA = unreleasedFlag(1302, "screenshot_metadata")
// TODO(b/266955521): Tracking bug
@JvmField val SCREENSHOT_DETECTION = releasedFlag(1303, "screenshot_detection")
@@ -657,7 +658,7 @@
@JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag(2200, "udfps_new_touch_detection")
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
// TODO(b/278622168): Tracking Bug
- @JvmField val BIOMETRIC_BP_STRONG = unreleasedFlag(2202, "biometric_bp_strong")
+ @JvmField val BIOMETRIC_BP_STRONG = releasedFlag(2202, "biometric_bp_strong")
// 2300 - stylus
@JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
@@ -714,20 +715,22 @@
val KEYBOARD_EDUCATION =
unreleasedFlag(2603, "keyboard_education", teamfood = false)
- // TODO(b/272036292): Tracking Bug
- @JvmField
- val LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION =
- releasedFlag(2602, "large_shade_granular_alpha_interpolation")
-
// TODO(b/277201412): Tracking Bug
@JvmField
val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION =
- unreleasedFlag(2805, "split_shade_subpixel_optimization", teamfood = true)
+ releasedFlag(2805, "split_shade_subpixel_optimization")
// TODO(b/278761837): Tracking Bug
@JvmField
val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
+ // 2900 - Zero Jank fixes. Naming convention is: zj_<bug number>_<cuj name>
+
+ // TODO:(b/285623104): Tracking bug
+ @JvmField
+ val ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD =
+ releasedFlag(2900, "zj_285570694_lockscreen_transition_from_aod")
+
// TODO(b/283084712): Tracking Bug
@JvmField
val IMPROVED_HUN_ANIMATIONS = unreleasedFlag(283084712, "improved_hun_animations")
@@ -736,4 +739,10 @@
@JvmField
val BIGPICTURE_NOTIFICATION_LAZY_LOADING =
unreleasedFlag(283447257, "bigpicture_notification_lazy_loading")
+
+ // 2900 - CentralSurfaces-related flags
+
+ // TODO(b/285174336): Tracking Bug
+ @JvmField
+ val USE_REPOS_FOR_BOUNCER_SHOWING = unreleasedFlag(2900, "use_repos_for_bouncer_showing")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index c71775b..5248364 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -914,7 +914,7 @@
mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS);
if (mTelecomManager != null) {
// Close shade so user sees the activity
- mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade);
+ mShadeController.cancelExpansionAndCollapseShade();
Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(
null /* number */);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 27a5974..bc07139 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -20,6 +20,7 @@
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
+import android.content.Intent
import android.content.UriMatcher
import android.content.pm.PackageManager
import android.content.pm.ProviderInfo
@@ -282,11 +283,11 @@
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ICON,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.IS_ENABLED,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
- .ENABLEMENT_INSTRUCTIONS,
+ .ENABLEMENT_EXPLANATION,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
.ENABLEMENT_ACTION_TEXT,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns
- .ENABLEMENT_COMPONENT_NAME,
+ .ENABLEMENT_ACTION_INTENT,
Contract.LockScreenQuickAffordances.AffordanceTable.Columns.CONFIGURE_INTENT,
)
)
@@ -298,13 +299,10 @@
representation.name,
representation.iconResourceId,
if (representation.isEnabled) 1 else 0,
- representation.instructions?.joinToString(
- Contract.LockScreenQuickAffordances.AffordanceTable
- .ENABLEMENT_INSTRUCTIONS_DELIMITER
- ),
+ representation.explanation,
representation.actionText,
- representation.actionComponentName,
- representation.configureIntent?.toUri(0),
+ representation.actionIntent?.toUri(Intent.URI_INTENT_SCHEME),
+ representation.configureIntent?.toUri(Intent.URI_INTENT_SCHEME),
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 573de97..0511314 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -49,7 +49,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
-import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIAppComponentFactoryBase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -72,13 +72,13 @@
/**
* Simple Slice provider that shows the current date.
*
- * Injection is handled by {@link SystemUIAppComponentFactory} +
+ * Injection is handled by {@link SystemUIAppComponentFactoryBase} +
* {@link com.android.systemui.dagger.GlobalRootComponent#inject(KeyguardSliceProvider)}.
*/
public class KeyguardSliceProvider extends SliceProvider implements
NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback,
NotificationMediaManager.MediaListener, StatusBarStateController.StateListener,
- SystemUIAppComponentFactory.ContextInitializer {
+ SystemUIAppComponentFactoryBase.ContextInitializer {
private static final String TAG = "KgdSliceProvider";
@@ -148,7 +148,7 @@
protected boolean mDozing;
private int mStatusBarState;
private boolean mMediaIsVisible;
- private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
+ private SystemUIAppComponentFactoryBase.ContextAvailableCallback mContextAvailableCallback;
@Inject
WakeLockLogger mWakeLockLogger;
@@ -533,7 +533,7 @@
@Override
public void setContextAvailableCallback(
- SystemUIAppComponentFactory.ContextAvailableCallback callback) {
+ SystemUIAppComponentFactoryBase.ContextAvailableCallback callback) {
mContextAvailableCallback = callback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 68e72c5..3646144 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -906,10 +906,7 @@
}
fun setWallpaperAppearAmount(amount: Float) {
- val animationAlpha = when {
- !powerManager.isInteractive -> 0f
- else -> amount
- }
+ val animationAlpha = amount
wallpaperTargets?.forEach { wallpaper ->
// SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 835a491..049aa0d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,7 @@
import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -36,8 +37,8 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -88,9 +89,11 @@
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
@@ -128,12 +131,14 @@
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -166,6 +171,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+import kotlinx.coroutines.CoroutineDispatcher;
/**
* Mediates requests related to the keyguard. This includes queries about the
@@ -442,11 +450,6 @@
private final int mDreamOpenAnimationDuration;
/**
- * The duration in milliseconds of the dream close animation.
- */
- private final int mDreamCloseAnimationDuration;
-
- /**
* The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them.
*/
@@ -704,6 +707,9 @@
}
}
break;
+ case TelephonyManager.SIM_STATE_UNKNOWN:
+ mPendingPinLock = false;
+ break;
default:
if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
break;
@@ -1132,49 +1138,57 @@
return;
}
- final RemoteAnimationTarget primary = apps[0];
+ mRemoteAnimationTarget = apps[0];
final boolean isDream = (apps[0].taskInfo != null
&& apps[0].taskInfo.topActivityType
== WindowConfiguration.ACTIVITY_TYPE_DREAM);
- final SyncRtSurfaceTransactionApplier applier =
- new SyncRtSurfaceTransactionApplier(
- mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+ final View localView = mKeyguardViewControllerLazy.get()
+ .getViewRootImpl().getView();
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(localView);
mContext.getMainExecutor().execute(() -> {
if (mUnoccludeAnimator != null) {
mUnoccludeAnimator.cancel();
}
+ if (isDream) {
+ initAlphaForAnimationTargets(wallpapers);
+ getRemoteSurfaceAlphaApplier().accept(0.0f);
+ mDreamingToLockscreenTransitionViewModel.get()
+ .startTransition();
+ return;
+ }
+
mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
- mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration
- : UNOCCLUDE_ANIMATION_DURATION);
+ mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
mUnoccludeAnimator.addUpdateListener(
animation -> {
final float animatedValue =
(float) animation.getAnimatedValue();
- final float surfaceHeight = primary.screenSpaceBounds.height();
+ final float surfaceHeight =
+ mRemoteAnimationTarget.screenSpaceBounds.height();
// Fade for all types of activities.
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
paramsBuilder =
new SyncRtSurfaceTransactionApplier.SurfaceParams
- .Builder(primary.leash)
+ .Builder(mRemoteAnimationTarget.leash)
.withAlpha(animatedValue);
- // Set translate if the occluding activity isn't Dream.
- if (!isDream) {
- mUnoccludeMatrix.setTranslate(
- 0f,
- (1f - animatedValue)
- * surfaceHeight
- * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
- paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
- mWindowCornerRadius);
- }
+ mUnoccludeMatrix.setTranslate(
+ 0f,
+ (1f - animatedValue)
+ * surfaceHeight
+ * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
+
+ paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
+ mWindowCornerRadius);
+
applier.scheduleApply(paramsBuilder.build());
});
mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -1196,6 +1210,34 @@
}
};
+ private static void initAlphaForAnimationTargets(
+ @android.annotation.NonNull RemoteAnimationTarget[] targets
+ ) {
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode != MODE_OPENING) continue;
+
+ try (Transaction t = new Transaction()) {
+ t.setAlpha(target.leash, 1.f);
+ t.apply();
+ }
+ }
+ }
+
+ private Consumer<Float> getRemoteSurfaceAlphaApplier() {
+ return (Float alpha) -> {
+ if (mRemoteAnimationTarget == null) return;
+ final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(localView);
+ SyncRtSurfaceTransactionApplier.SurfaceParams
+ params =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(mRemoteAnimationTarget.leash)
+ .withAlpha(alpha).build();
+ applier.scheduleApply(params);
+ };
+ }
+
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
@@ -1226,6 +1268,10 @@
private FeatureFlags mFeatureFlags;
private final UiEventLogger mUiEventLogger;
private final SessionTracker mSessionTracker;
+ private final CoroutineDispatcher mMainDispatcher;
+ private final Lazy<DreamingToLockscreenTransitionViewModel>
+ mDreamingToLockscreenTransitionViewModel;
+ private RemoteAnimationTarget mRemoteAnimationTarget;
/**
* Injected constructor. See {@link KeyguardModule}.
@@ -1265,7 +1311,9 @@
FeatureFlags featureFlags,
SecureSettings secureSettings,
SystemSettings systemSettings,
- SystemClock systemClock) {
+ SystemClock systemClock,
+ @Main CoroutineDispatcher mainDispatcher,
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1324,11 +1372,13 @@
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
- mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
mFeatureFlags = featureFlags;
mUiEventLogger = uiEventLogger;
mSessionTracker = sessionTracker;
+
+ mMainDispatcher = mainDispatcher;
+ mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
}
public void userActivity() {
@@ -1447,6 +1497,13 @@
mUpdateMonitor.registerCallback(mUpdateCallback);
adjustStatusBarLocked();
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
+
+ ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();
+ if (viewRootImpl != null) {
+ collectFlow(viewRootImpl.getView(),
+ mDreamingToLockscreenTransitionViewModel.get().getDreamOverlayAlpha(),
+ getRemoteSurfaceAlphaApplier(), mMainDispatcher);
+ }
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
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 ab1341e..5622df1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
@@ -52,6 +53,7 @@
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
@@ -76,6 +78,8 @@
import java.util.concurrent.Executor;
+import kotlinx.coroutines.CoroutineDispatcher;
+
/**
* Dagger Module providing keyguard.
*/
@@ -136,7 +140,9 @@
FeatureFlags featureFlags,
SecureSettings secureSettings,
SystemSettings systemSettings,
- SystemClock systemClock) {
+ SystemClock systemClock,
+ @Main CoroutineDispatcher mainDispatcher,
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -174,7 +180,9 @@
featureFlags,
secureSettings,
systemSettings,
- systemClock);
+ systemClock,
+ mainDispatcher,
+ dreamingToLockscreenTransitionViewModel);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index abb63c4..f3fc809 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import androidx.annotation.DrawableRes
@@ -34,6 +35,7 @@
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.Companion.appStoreIntent
import com.android.systemui.util.kotlin.getOrNull
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -76,18 +78,44 @@
component.getControlsListingController().getOrNull()?.getCurrentServices()
val hasFavorites =
component.getControlsController().getOrNull()?.getFavorites()?.isNotEmpty() == true
- if (currentServices.isNullOrEmpty() || !hasFavorites) {
- return KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- instructions =
- listOf(
+ val componentPackageName = component.getPackageName()
+ when {
+ currentServices.isNullOrEmpty() && !componentPackageName.isNullOrEmpty() -> {
+ // No home app installed but we know which app we want to install.
+ return disabledPickerState(
+ explanation =
context.getString(
- R.string.keyguard_affordance_enablement_dialog_home_instruction_1
+ R.string.home_quick_affordance_unavailable_install_the_app
),
+ actionText = context.getString(R.string.install_app),
+ actionIntent = appStoreIntent(context, componentPackageName),
+ )
+ }
+ currentServices.isNullOrEmpty() && componentPackageName.isNullOrEmpty() -> {
+ // No home app installed and we don't know which app we want to install.
+ return disabledPickerState(
+ explanation =
context.getString(
- R.string.keyguard_affordance_enablement_dialog_home_instruction_2
+ R.string.home_quick_affordance_unavailable_install_the_app
),
- ),
- )
+ )
+ }
+ !hasFavorites -> {
+ // Home app installed but no favorites selected.
+ val activityClass = component.getControlsUiController().get().resolveActivity()
+ return disabledPickerState(
+ explanation =
+ context.getString(
+ R.string.home_quick_affordance_unavailable_configure_the_app
+ ),
+ actionText = context.getString(R.string.controls_open_app),
+ actionIntent =
+ Intent().apply {
+ component = ComponentName(context, activityClass)
+ putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+ },
+ )
+ }
}
return KeyguardQuickAffordanceConfig.PickerScreenState.Default()
@@ -172,6 +200,20 @@
}
}
+ private fun disabledPickerState(
+ explanation: String,
+ actionText: String? = null,
+ actionIntent: Intent? = null,
+ ): KeyguardQuickAffordanceConfig.PickerScreenState.Disabled {
+ check(actionIntent == null || actionText != null)
+
+ return KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
+ explanation = explanation,
+ actionText = actionText,
+ actionIntent = actionIntent,
+ )
+ }
+
companion object {
private const val TAG = "HomeControlsKeyguardQuickAffordanceConfig"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 28dc5bd..320d158 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -18,11 +18,13 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.app.AlertDialog
+import android.content.Context
import android.content.Intent
+import android.net.Uri
+import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
-import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import kotlinx.coroutines.flow.Flow
/** Defines interface that can act as data source for a single quick affordance model. */
@@ -80,37 +82,35 @@
/**
* The picker shows the item for selecting this affordance as disabled. Clicking on it will
- * show the given instructions to the user. If [actionText] and [actionComponentName] are
- * provided (optional) a button will be shown to open an activity to help the user complete
- * the steps described in the instructions.
+ * show the given instructions to the user. If [actionText] and [actionIntent] are provided
+ * (optional) a button will be shown to open an activity to help the user complete the steps
+ * described in the instructions.
*/
data class Disabled(
- /** List of human-readable instructions for setting up the quick affordance. */
- val instructions: List<String>,
+ /** Human-readable explanation as to why the quick affordance is current disabled. */
+ val explanation: String,
/**
* Optional text to display on a button that the user can click to start a flow to go
* and set up the quick affordance and make it enabled.
*/
val actionText: String? = null,
/**
- * Optional component name to be able to build an `Intent` that opens an `Activity` for
- * the user to be able to set up the quick affordance and make it enabled.
- *
- * This is either just an action for the `Intent` or a package name and action,
- * separated by
- * [Contract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR] for
- * convenience, you can use the [componentName] function.
+ * Optional [Intent] that opens an `Activity` for the user to be able to set up the
+ * quick affordance and make it enabled.
*/
- val actionComponentName: String? = null,
+ val actionIntent: Intent? = null,
) : PickerScreenState() {
init {
- check(instructions.isNotEmpty()) { "Instructions must not be empty!" }
+ check(explanation.isNotEmpty()) { "Explanation must not be empty!" }
check(
- (actionText.isNullOrEmpty() && actionComponentName.isNullOrEmpty()) ||
- (!actionText.isNullOrEmpty() && !actionComponentName.isNullOrEmpty())
+ (actionText.isNullOrEmpty() && actionIntent == null) ||
+ (!actionText.isNullOrEmpty() && actionIntent != null)
) {
- "actionText and actionComponentName must either both be null/empty or both be" +
- " non-empty!"
+ """
+ actionText and actionIntent must either both be null/empty or both be
+ non-null and non-empty!
+ """
+ .trimIndent()
}
}
}
@@ -163,17 +163,33 @@
}
companion object {
- fun componentName(
- packageName: String? = null,
- action: String?,
- ): String? {
- return when {
- action.isNullOrEmpty() -> null
- !packageName.isNullOrEmpty() ->
- "$packageName${Contract.LockScreenQuickAffordances.AffordanceTable
- .COMPONENT_NAME_SEPARATOR}$action"
- else -> action
+
+ /**
+ * Returns an [Intent] that can be used to start an activity that opens the app store app to
+ * a page showing the app with the passed-in [packageName].
+ *
+ * If the feature isn't enabled on this device/variant/configuration, a `null` will be
+ * returned.
+ */
+ fun appStoreIntent(context: Context, packageName: String?): Intent? {
+ if (packageName.isNullOrEmpty()) {
+ return null
+ }
+
+ val appStorePackageName = context.getString(R.string.config_appStorePackageName)
+ val linkTemplate = context.getString(R.string.config_appStoreAppLinkTemplate)
+ if (appStorePackageName.isEmpty() || linkTemplate.isEmpty()) {
+ return null
+ }
+
+ check(linkTemplate.contains(APP_PACKAGE_NAME_PLACEHOLDER))
+
+ return Intent(Intent.ACTION_VIEW).apply {
+ setPackage(appStorePackageName)
+ data = Uri.parse(linkTemplate.replace(APP_PACKAGE_NAME_PLACEHOLDER, packageName))
}
}
+
+ private const val APP_PACKAGE_NAME_PLACEHOLDER = "\$packageName"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index 0d54ab9..20ed549 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -80,16 +80,14 @@
return when {
!controller.isAvailableOnDevice ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
- !controller.isAbleToOpenCameraApp ->
+ !controller.isAbleToOpenCameraApp -> {
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- instructions =
- listOf(
- context.getString(
- R.string
- .keyguard_affordance_enablement_dialog_qr_scanner_instruction
- ),
+ explanation =
+ context.getString(
+ R.string.qr_scanner_quick_affordance_unavailable_explanation
),
)
+ }
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 9db3c22..c019d21 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -100,19 +100,20 @@
return when {
!walletController.walletClient.isWalletServiceAvailable ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
- !isWalletAvailable() || queryCards().isEmpty() -> {
+ !isWalletAvailable() ->
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- instructions =
- listOf(
- context.getString(
- R.string.keyguard_affordance_enablement_dialog_wallet_instruction_1
- ),
- context.getString(
- R.string.keyguard_affordance_enablement_dialog_wallet_instruction_2
- ),
+ explanation =
+ context.getString(
+ R.string.wallet_quick_affordance_unavailable_install_the_app
),
)
- }
+ queryCards().isEmpty() ->
+ KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
+ explanation =
+ context.getString(
+ R.string.wallet_quick_affordance_unavailable_configure_the_app
+ ),
+ )
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
}
}
@@ -147,9 +148,7 @@
}
private fun isWalletAvailable() =
- with(walletController.walletClient) {
- isWalletServiceAvailable && isWalletFeatureAvailable
- }
+ with(walletController.walletClient) { isWalletServiceAvailable && isWalletFeatureAvailable }
private fun state(
isFeatureEnabled: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 9621f03..f9e9a93 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -26,6 +26,7 @@
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.Dumpable
import com.android.systemui.R
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -34,7 +35,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
index 96c94d7..34f6b4d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.repository
import android.content.Context
+import android.content.Intent
import android.os.UserHandle
import android.util.LayoutDirection
import com.android.systemui.Dumpable
@@ -174,12 +175,23 @@
iconResourceId = config.pickerIconResourceId,
isEnabled =
pickerState is KeyguardQuickAffordanceConfig.PickerScreenState.Default,
- instructions = disabledPickerState?.instructions,
+ explanation = disabledPickerState?.explanation,
actionText = disabledPickerState?.actionText,
- actionComponentName = disabledPickerState?.actionComponentName,
- configureIntent = defaultPickerState?.configureIntent,
+ actionIntent =
+ disabledPickerState?.actionIntent?.apply {
+ addFlags(
+ Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
+ )
+ },
+ configureIntent =
+ defaultPickerState?.configureIntent?.apply {
+ addFlags(
+ Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
+ )
+ },
)
}
+ .sortedBy { it.name }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 4055fd0..246ee33 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -17,9 +17,11 @@
package com.android.systemui.keyguard.data.repository
import com.android.systemui.CoreStartable
-import com.android.systemui.keyguard.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.keyguard.bouncer.data.repository.BouncerMessageRepositoryImpl
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageAuditLogger
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageAuditLogger
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index c94aa11..84cd3ef 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -165,35 +165,28 @@
// An animator was provided, so use it to run the transition
animator.setFloatValues(startingValue, 1f)
animator.duration = ((1f - startingValue) * animator.duration).toLong()
- val updateListener =
- object : AnimatorUpdateListener {
- override fun onAnimationUpdate(animation: ValueAnimator) {
- emitTransition(
- TransitionStep(
- info,
- (animation.getAnimatedValue() as Float),
- TransitionState.RUNNING
- )
- )
- }
- }
+ val updateListener = AnimatorUpdateListener { animation ->
+ emitTransition(
+ TransitionStep(
+ info,
+ (animation.animatedValue as Float),
+ TransitionState.RUNNING
+ )
+ )
+ }
val adapter =
object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
}
override fun onAnimationCancel(animation: Animator) {
- endAnimation(animation, lastStep.value, TransitionState.CANCELED)
+ endAnimation(lastStep.value, TransitionState.CANCELED)
}
override fun onAnimationEnd(animation: Animator) {
- endAnimation(animation, 1f, TransitionState.FINISHED)
+ endAnimation(1f, TransitionState.FINISHED)
}
- private fun endAnimation(
- animation: Animator,
- value: Float,
- state: TransitionState
- ) {
+ private fun endAnimation(value: Float, state: TransitionState) {
emitTransition(TransitionStep(info, value, state))
animator.removeListener(this)
animator.removeUpdateListener(updateListener)
@@ -206,7 +199,7 @@
return@startTransition null
}
?: run {
- emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+ emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
// No animator, so it's manual. Provide a mechanism to callback
updateTransitionId = UUID.randomUUID()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 323fc31..ee2c2df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -52,7 +52,7 @@
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (wakefulnessModel, lastStartedTransition) ->
if (
- wakefulnessModel.isStartingToWake() &&
+ wakefulnessModel.isStartingToWakeOrAwake() &&
lastStartedTransition.to == KeyguardState.DOZING
) {
keyguardTransitionRepository.startTransition(
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 36c8eb1..ccf4bc1 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
@@ -23,7 +23,6 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
-import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
@@ -48,39 +47,23 @@
) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
override fun start() {
- listenForDreamingToLockscreen()
listenForDreamingToOccluded()
listenForDreamingToGone()
listenForDreamingToDozing()
}
- private fun listenForDreamingToLockscreen() {
+ fun startToLockscreenTransition() {
scope.launch {
- keyguardInteractor.isAbleToDream
- .sample(
- combine(
- keyguardInteractor.dozeTransitionModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
- ),
- ::toTriple
+ if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.DREAMING,
+ KeyguardState.LOCKSCREEN,
+ getAnimator(TO_LOCKSCREEN_DURATION),
+ )
)
- .collect { (isDreaming, dozeTransitionModel, lastStartedTransition) ->
- if (
- !isDreaming &&
- isDozeOff(dozeTransitionModel.to) &&
- lastStartedTransition.to == KeyguardState.DREAMING
- ) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
- }
- }
+ }
}
}
@@ -173,6 +156,6 @@
companion object {
private val DEFAULT_DURATION = 500.milliseconds
- val TO_LOCKSCREEN_DURATION = 1183.milliseconds
+ val TO_LOCKSCREEN_DURATION = 1167.milliseconds
}
}
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 d13d5ad..228290a 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
@@ -19,13 +19,13 @@
import android.app.StatusBarManager
import android.graphics.Point
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -114,7 +114,7 @@
isDreaming && isDozeOff(dozeTransitionModel.to)
}
.sample(wakefulnessModel) { isAbleToDream, wakefulnessModel ->
- isAbleToDream && wakefulnessModel.isStartingToWake()
+ isAbleToDream && wakefulnessModel.isStartingToWakeOrAwake()
}
.flatMapLatest { isAbleToDream ->
flow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 2275337..ea9c2b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -35,6 +35,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceRegistry
@@ -77,6 +78,7 @@
private val logger: KeyguardQuickAffordancesMetricsLogger,
private val devicePolicyManager: DevicePolicyManager,
private val dockManager: DockManager,
+ private val biometricSettingsRepository: BiometricSettingsRepository,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@Application private val appContext: Context,
) {
@@ -107,9 +109,10 @@
quickAffordanceAlwaysVisible(position),
keyguardInteractor.isDozing,
keyguardInteractor.isKeyguardShowing,
- keyguardInteractor.isQuickSettingsVisible
- ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible ->
- if (!isDozing && isKeyguardShowing && !isQuickSettingsVisible) {
+ keyguardInteractor.isQuickSettingsVisible,
+ biometricSettingsRepository.isCurrentUserInLockdown,
+ ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
+ if (!isDozing && isKeyguardShowing && !isQuickSettingsVisible && !isUserInLockdown) {
affordance
} else {
KeyguardQuickAffordanceModel.Hidden
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 da0ada1..42f12f8 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
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -29,10 +30,14 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
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.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to the keyguard transitions. */
@SysUISingleton
@@ -40,6 +45,7 @@
@Inject
constructor(
private val repository: KeyguardTransitionRepository,
+ @Application val scope: CoroutineScope,
) {
/** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> =
@@ -108,10 +114,17 @@
val finishedKeyguardTransitionStep: Flow<TransitionStep> =
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
- /** The last completed [KeyguardState] transition */
- val finishedKeyguardState: Flow<KeyguardState> =
- finishedKeyguardTransitionStep.map { step -> step.to }
+ /** The destination state of the last started transition */
+ val startedKeyguardState: StateFlow<KeyguardState> =
+ startedKeyguardTransitionStep
+ .map { step -> step.to }
+ .stateIn(scope, SharingStarted.Eagerly, KeyguardState.OFF)
+ /** The last completed [KeyguardState] transition */
+ val finishedKeyguardState: StateFlow<KeyguardState> =
+ finishedKeyguardTransitionStep
+ .map { step -> step.to }
+ .stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN)
/**
* The amount of transition into or out of the given [KeyguardState].
*
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 6b515da..8b749f0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -19,6 +19,8 @@
import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
index e7e9159..c6320de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
@@ -32,8 +32,8 @@
/** Whether this quick affordance is enabled. */
val isEnabled: Boolean = true,
- /** If not enabled, the list of user-visible steps to re-enable it. */
- val instructions: List<String>? = null,
+ /** If not enabled, a user-visible explanation as to why. */
+ val explanation: String? = null,
/**
* If not enabled, an optional label for a button that takes the user to a destination where
@@ -41,11 +41,8 @@
*/
val actionText: String? = null,
- /**
- * If not enabled, an optional component name (package and action) for a button that takes the
- * user to a destination where they can re-enable it.
- */
- val actionComponentName: String? = null,
+ /** Optional [Intent] to use to start an activity to re-enable this affordance. */
+ val actionIntent: Intent? = null,
/** Optional [Intent] to use to start an activity to configure this affordance. */
val configureIntent: Intent? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index dd57713..cfd9e08 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -33,6 +33,8 @@
fun isDeviceInteractive() = !isAsleep()
+ fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE
+
fun isStartingToSleepFromPowerButton() =
isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON
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 db23109..1c2e85b 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
@@ -404,8 +404,7 @@
val darkClockColor = wallpaperColorScheme?.accent2?.s600
/** Note that when [wallpaperColors] is null, isWallpaperDark is true. */
val isWallpaperDark: Boolean =
- (wallpaperColors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) !=
- WallpaperColors.HINT_SUPPORTS_DARK_TEXT
+ (wallpaperColors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0
clock.events.onSeedColorChanged(
if (isWallpaperDark) lightClockColor else darkClockColor
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 2c9a9b3..9ca4bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,15 +16,17 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
/**
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -34,22 +36,32 @@
class DreamingToLockscreenTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
) {
+ fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
+
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_LOCKSCREEN_DURATION,
- transitionFlow = interactor.dreamingToLockscreenTransition,
+ transitionFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition,
)
+ val transitionEnded =
+ keyguardTransitionInteractor.dreamingToLockscreenTransition.filter { step ->
+ step.transitionState == TransitionState.FINISHED ||
+ step.transitionState == TransitionState.CANCELED
+ }
+
/** Dream overlay y-translation on exit */
fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> {
return transitionAnimation.createFlow(
- duration = 600.milliseconds,
+ duration = TO_LOCKSCREEN_DURATION,
onStep = { it * translatePx },
- interpolator = EMPHASIZED_ACCELERATE,
+ interpolator = EMPHASIZED,
)
}
+
/** Dream overlay views alpha - fade out */
val dreamOverlayAlpha: Flow<Float> =
transitionAnimation.createFlow(
@@ -65,7 +77,7 @@
// Reset on cancel or finish
onFinish = { 0f },
onCancel = { 0f },
- interpolator = EMPHASIZED_DECELERATE,
+ interpolator = EMPHASIZED,
)
}
@@ -76,12 +88,4 @@
duration = 250.milliseconds,
onStep = { it },
)
-
- companion object {
- /* Length of time before ending the dream activity, in order to start unoccluding */
- val DREAM_ANIMATION_DURATION = 250.milliseconds
- @JvmField
- val LOCKSCREEN_ANIMATION_DURATION_MS =
- (TO_LOCKSCREEN_DURATION - DREAM_ANIMATION_DURATION).inWholeMilliseconds
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index c6187dd..a3ae67d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -33,7 +33,7 @@
class LockscreenToDreamingTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
+ interactor: KeyguardTransitionInteractor,
) {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
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 68810f9..44e1fd1 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
@@ -17,10 +17,10 @@
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.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.statusbar.SysuiStatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt b/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
index 3be4499..3226865 100644
--- a/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
@@ -16,8 +16,8 @@
package com.android.systemui.log
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.log.dagger.BouncerLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index c41f82b..8d3c6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -38,8 +38,6 @@
import com.android.internal.app.chooser.NotSelectableTargetInfo
import com.android.internal.app.chooser.TargetInfo
import com.android.systemui.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
@@ -53,7 +51,6 @@
class MediaProjectionAppSelectorActivity(
private val componentFactory: MediaProjectionAppSelectorComponent.Factory,
private val activityLauncher: AsyncActivityLauncher,
- private val featureFlags: FeatureFlags,
/** This is used to override the dependency in a screenshot test */
@VisibleForTesting
private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)?
@@ -62,9 +59,8 @@
@Inject
constructor(
componentFactory: MediaProjectionAppSelectorComponent.Factory,
- activityLauncher: AsyncActivityLauncher,
- featureFlags: FeatureFlags
- ) : this(componentFactory, activityLauncher, featureFlags, listControllerFactory = null)
+ activityLauncher: AsyncActivityLauncher
+ ) : this(componentFactory, activityLauncher, listControllerFactory = null)
private lateinit var configurationController: ConfigurationController
private lateinit var controller: MediaProjectionAppSelectorController
@@ -108,11 +104,7 @@
override fun appliedThemeResId(): Int = R.style.Theme_SystemUI_MediaProjectionAppSelector
override fun createBlockerEmptyStateProvider(): EmptyStateProvider =
- if (featureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
- component.emptyStateProvider
- } else {
- object : EmptyStateProvider {}
- }
+ component.emptyStateProvider
override fun createListController(userHandle: UserHandle): ResolverListController =
listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 14386c1..0819d0d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -248,9 +248,9 @@
private final FeatureFlags mFeatureFlags;
private final GlobalSettings mGlobalSettings;
- // TODO(b/281032715): Consider making this as a final variable. For now having a null check
- // due to unit test failure. (Perhaps missing some setup)
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
+ private boolean mWasPlaying = false;
+ private boolean mButtonClicked = false;
private ContentObserver mAnimationScaleObserver = new ContentObserver(null) {
@Override
@@ -582,6 +582,25 @@
if (!mMetadataAnimationHandler.isRunning()) {
mMediaViewController.refreshState();
}
+
+ // Turbulence noise
+ if (shouldPlayTurbulenceNoise()) {
+ if (mTurbulenceNoiseAnimationConfig == null) {
+ mTurbulenceNoiseAnimationConfig =
+ createTurbulenceNoiseAnimation();
+ }
+ // Color will be correctly updated in ColorSchemeTransition.
+ mTurbulenceNoiseController.play(
+ mTurbulenceNoiseAnimationConfig
+ );
+ mMainExecutor.executeDelayed(
+ mTurbulenceNoiseController::finish,
+ TURBULENCE_NOISE_PLAY_DURATION
+ );
+ }
+ mButtonClicked = false;
+ mWasPlaying = isPlaying();
+
Trace.endSection();
}
@@ -1155,21 +1174,14 @@
if (!mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) {
mLogger.logTapAction(button.getId(), mUid, mPackageName, mInstanceId);
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT);
+ // Used to determine whether to play turbulence noise.
+ mWasPlaying = isPlaying();
+ mButtonClicked = true;
+
action.run();
+
if (mFeatureFlags.isEnabled(Flags.UMO_SURFACE_RIPPLE)) {
mMultiRippleController.play(createTouchRippleAnimation(button));
- if (mFeatureFlags.isEnabled(Flags.UMO_TURBULENCE_NOISE)) {
- if (mTurbulenceNoiseAnimationConfig == null) {
- mTurbulenceNoiseAnimationConfig =
- createTurbulenceNoiseAnimation();
- }
- // Color will be correctly updated in ColorSchemeTransition.
- mTurbulenceNoiseController.play(mTurbulenceNoiseAnimationConfig);
- mMainExecutor.executeDelayed(
- mTurbulenceNoiseController::finish,
- TURBULENCE_NOISE_PLAY_DURATION
- );
- }
}
if (icon instanceof Animatable) {
@@ -1208,6 +1220,11 @@
);
}
+ private boolean shouldPlayTurbulenceNoise() {
+ return mFeatureFlags.isEnabled(Flags.UMO_TURBULENCE_NOISE) && mButtonClicked && !mWasPlaying
+ && isPlaying();
+ }
+
private TurbulenceNoiseAnimationConfig createTurbulenceNoiseAnimation() {
return new TurbulenceNoiseAnimationConfig(
/* gridCount= */ 2.14f,
@@ -1218,12 +1235,12 @@
/* color= */ mColorSchemeTransition.getAccentPrimary().getCurrentColor(),
/* backgroundColor= */ Color.BLACK,
/* opacity= */ 51,
- /* width= */ mMediaViewHolder.getMultiRippleView().getWidth(),
- /* height= */ mMediaViewHolder.getMultiRippleView().getHeight(),
+ /* width= */ mMediaViewHolder.getTurbulenceNoiseView().getWidth(),
+ /* height= */ mMediaViewHolder.getTurbulenceNoiseView().getHeight(),
TurbulenceNoiseAnimationConfig.DEFAULT_MAX_DURATION_IN_MILLIS,
/* easeInDuration= */ 1350f,
/* easeOutDuration= */ 1350f,
- this.getContext().getResources().getDisplayMetrics().density,
+ getContext().getResources().getDisplayMetrics().density,
BlendMode.SCREEN,
/* onAnimationEnd= */ null,
/* lumaMatteBlendFactor= */ 0.26f,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 88ffa8d..318cd99 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -24,7 +24,6 @@
import android.content.res.ColorStateList;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -175,9 +174,8 @@
mCurrentActivePosition = position;
updateFullItemClickListener(v -> onItemClick(v, device));
setSingleLineLayout(getItemTitle(device));
- initMutingExpectedDevice();
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
- && device.hasSubtext()) {
+ initFakeActiveDevice();
+ } else if (device.hasSubtext()) {
boolean isActiveWithOngoingSession =
(device.hasOngoingSession() && (currentlyConnected || isDeviceIncluded(
mController.getSelectedMediaDevice(), device)));
@@ -267,6 +265,27 @@
setUpDeviceIcon(device);
updateFullItemClickListener(v -> cancelMuteAwaitConnection());
setSingleLineLayout(getItemTitle(device));
+ } else if (device.hasOngoingSession()) {
+ mCurrentActivePosition = position;
+ if (device.isHostForOngoingSession()) {
+ updateTitleIcon(R.drawable.media_output_icon_volume,
+ mController.getColorItemContent());
+ updateEndClickAreaAsSessionEditing(device);
+ mEndClickIcon.setVisibility(View.VISIBLE);
+ setSingleLineLayout(getItemTitle(device), true /* showSeekBar */,
+ false /* showProgressBar */, false /* showCheckBox */,
+ true /* showEndTouchArea */);
+ initSeekbar(device, isCurrentSeekbarInvisible);
+ } else {
+ updateDeviceStatusIcon(mContext.getDrawable(
+ R.drawable.ic_sound_bars_anim));
+ mStatusIcon.setVisibility(View.VISIBLE);
+ updateSingleLineLayoutContentAlpha(
+ updateClickActionBasedOnSelectionBehavior(device)
+ ? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
+ setSingleLineLayout(getItemTitle(device));
+ initFakeActiveDevice();
+ }
} else if (mController.isCurrentConnectedDeviceRemote()
&& !mController.getSelectableMediaDevice().isEmpty()) {
//If device is connected and there's other selectable devices, layout as
@@ -351,7 +370,7 @@
ColorStateList.valueOf(mController.getColorItemContent()));
mEndClickIcon.setOnClickListener(
v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v));
- mEndTouchArea.setOnClickListener(v -> mCheckBox.performClick());
+ mEndTouchArea.setOnClickListener(v -> mEndClickIcon.performClick());
}
public void updateEndClickAreaColor(int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 01f7904..b88eba9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -188,6 +188,7 @@
mContainerLayout.setContentDescription(null);
mTitleText.setTextColor(mController.getColorItemContent());
mSubTitleText.setTextColor(mController.getColorItemContent());
+ mSubTitleText.setSelected(true);
mTwoLineTitleText.setTextColor(mController.getColorItemContent());
mVolumeValueText.setTextColor(mController.getColorItemContent());
mSeekBar.setProgressTintList(
@@ -417,7 +418,7 @@
mIconAreaLayout.setOnClickListener(listener);
}
- void initMutingExpectedDevice() {
+ void initFakeActiveDevice() {
disableSeekBar();
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 1d8fe72..e61650f 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -18,9 +18,9 @@
import android.content.ComponentName
import android.os.UserHandle
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
@@ -32,7 +32,7 @@
constructor(
private val recentTaskListProvider: RecentTaskListProvider,
private val view: MediaProjectionAppSelectorView,
- private val flags: FeatureFlags,
+ private val devicePolicyResolver: ScreenCaptureDevicePolicyResolver,
@HostUserHandle private val hostUserHandle: UserHandle,
@MediaProjectionAppSelector private val scope: CoroutineScope,
@MediaProjectionAppSelector private val appSelectorComponentName: ComponentName,
@@ -54,11 +54,13 @@
scope.cancel()
}
- /**
- * Removes all recent tasks that are different from the profile of the host app to avoid any
- * cross-profile sharing
- */
- private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = this
+ /** Removes all recent tasks that should be blocked according to the policy */
+ private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = filter {
+ devicePolicyResolver.isScreenCaptureAllowed(
+ targetAppUserHandle = UserHandle.of(it.userId),
+ hostAppUserHandle = hostUserHandle
+ )
+ }
private fun List<RecentTask>.filterAppSelector(): List<RecentTask> = filter {
// Only take tasks that is not the app selector
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt
index 6bd33e7..b11a244 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt
@@ -47,7 +47,7 @@
return false
}
- if (!hostAppUserHandle.isWorkProfile() && personalProfileScreenCaptureDisabled) {
+ if (personalProfileScreenCaptureDisabled) {
// Disable screen capturing as personal apps should not capture the screen
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index cb8d87a..cf192f9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -254,8 +254,9 @@
private boolean mDeferSetIsOnLeftEdge;
private boolean mIsAttached;
- private boolean mIsGesturalModeEnabled;
+ private boolean mIsGestureHandlingEnabled;
private boolean mIsTrackpadConnected;
+ private boolean mInGestureNavMode;
private boolean mUsingThreeButtonNav;
private boolean mIsEnabled;
private boolean mIsNavBarShownTransiently;
@@ -562,9 +563,7 @@
mInputManager.registerInputDeviceListener(mInputDeviceListener, mMainHandler);
int [] inputDevices = mInputManager.getInputDeviceIds();
for (int inputDeviceId : inputDevices) {
- if (isTrackpadDevice(inputDeviceId)) {
- mIsTrackpadConnected = true;
- }
+ mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
}
}
updateIsEnabled();
@@ -589,8 +588,7 @@
*/
public void onNavigationModeChanged(int mode) {
mUsingThreeButtonNav = QuickStepContract.isLegacyMode(mode);
- mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode) || (
- mIsTrackpadGestureFeaturesEnabled && mUsingThreeButtonNav && mIsTrackpadConnected);
+ mInGestureNavMode = QuickStepContract.isGesturalMode(mode);
updateIsEnabled();
updateCurrentUserResources();
}
@@ -613,81 +611,83 @@
private void updateIsEnabled() {
try {
Trace.beginSection("EdgeBackGestureHandler#updateIsEnabled");
- updateIsEnabledTraced();
+
+ mIsGestureHandlingEnabled =
+ mInGestureNavMode || (mIsTrackpadGestureFeaturesEnabled && mUsingThreeButtonNav
+ && mIsTrackpadConnected);
+ boolean isEnabled = mIsAttached && mIsGestureHandlingEnabled;
+ if (isEnabled == mIsEnabled) {
+ return;
+ }
+ mIsEnabled = isEnabled;
+ disposeInputChannel();
+
+ if (mEdgeBackPlugin != null) {
+ mEdgeBackPlugin.onDestroy();
+ mEdgeBackPlugin = null;
+ }
+
+ if (!mIsEnabled) {
+ mGestureNavigationSettingsObserver.unregister();
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "Unregister display listener");
+ }
+ mPluginManager.removePluginListener(this);
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
+ mTaskStackListener);
+ DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
+ mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(null));
+
+ try {
+ mWindowManagerService.unregisterSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ } catch (RemoteException | IllegalArgumentException e) {
+ Log.e(TAG, "Failed to unregister window manager callbacks", e);
+ }
+
+ } else {
+ mGestureNavigationSettingsObserver.register();
+ updateDisplaySize();
+ if (DEBUG_MISSING_GESTURE) {
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "Register display listener");
+ }
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(
+ mTaskStackListener);
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ mMainExecutor::execute, mOnPropertiesChangedListener);
+ mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(
+ mOnIsInPipStateChangedListener));
+ mDesktopModeOptional.ifPresent(
+ dm -> dm.addDesktopGestureExclusionRegionListener(
+ mDesktopCornersChangedListener, mMainExecutor));
+
+ try {
+ mWindowManagerService.registerSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ } catch (RemoteException | IllegalArgumentException e) {
+ Log.e(TAG, "Failed to register window manager callbacks", e);
+ }
+
+ // Register input event receiver
+ mInputMonitor = mContext.getSystemService(InputManager.class).monitorGestureInput(
+ "edge-swipe", mDisplayId);
+ mInputEventReceiver = new InputChannelCompat.InputEventReceiver(
+ mInputMonitor.getInputChannel(), Looper.getMainLooper(),
+ Choreographer.getInstance(), this::onInputEvent);
+
+ // Add a nav bar panel window
+ mIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE);
+ resetEdgeBackPlugin();
+ mPluginManager.addPluginListener(
+ this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
+ }
+ // Update the ML model resources.
+ updateMLModelState();
} finally {
Trace.endSection();
}
}
- private void updateIsEnabledTraced() {
- boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
- if (isEnabled == mIsEnabled) {
- return;
- }
- mIsEnabled = isEnabled;
- disposeInputChannel();
-
- if (mEdgeBackPlugin != null) {
- mEdgeBackPlugin.onDestroy();
- mEdgeBackPlugin = null;
- }
-
- if (!mIsEnabled) {
- mGestureNavigationSettingsObserver.unregister();
- if (DEBUG_MISSING_GESTURE) {
- Log.d(DEBUG_MISSING_GESTURE_TAG, "Unregister display listener");
- }
- mPluginManager.removePluginListener(this);
- TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
- DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
- mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(null));
-
- try {
- mWindowManagerService.unregisterSystemGestureExclusionListener(
- mGestureExclusionListener, mDisplayId);
- } catch (RemoteException | IllegalArgumentException e) {
- Log.e(TAG, "Failed to unregister window manager callbacks", e);
- }
-
- } else {
- mGestureNavigationSettingsObserver.register();
- updateDisplaySize();
- if (DEBUG_MISSING_GESTURE) {
- Log.d(DEBUG_MISSING_GESTURE_TAG, "Register display listener");
- }
- TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- mMainExecutor::execute, mOnPropertiesChangedListener);
- mPipOptional.ifPresent(
- pip -> pip.setOnIsInPipStateChangedListener(mOnIsInPipStateChangedListener));
- mDesktopModeOptional.ifPresent(
- dm -> dm.addDesktopGestureExclusionRegionListener(
- mDesktopCornersChangedListener, mMainExecutor));
-
- try {
- mWindowManagerService.registerSystemGestureExclusionListener(
- mGestureExclusionListener, mDisplayId);
- } catch (RemoteException | IllegalArgumentException e) {
- Log.e(TAG, "Failed to register window manager callbacks", e);
- }
-
- // Register input event receiver
- mInputMonitor = mContext.getSystemService(InputManager.class).monitorGestureInput(
- "edge-swipe", mDisplayId);
- mInputEventReceiver = new InputChannelCompat.InputEventReceiver(
- mInputMonitor.getInputChannel(), Looper.getMainLooper(),
- Choreographer.getInstance(), this::onInputEvent);
-
- // Add a nav bar panel window
- mIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE);
- resetEdgeBackPlugin();
- mPluginManager.addPluginListener(
- this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
- }
- // Update the ML model resources.
- updateMLModelState();
- }
-
@Override
public void onPluginConnected(NavigationEdgeBackPlugin plugin, Context context) {
setEdgeBackPlugin(plugin);
@@ -762,9 +762,9 @@
}
private void updateMLModelState() {
- boolean newState =
- mIsGesturalModeEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false);
+ boolean newState = mIsGestureHandlingEnabled && DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false);
if (newState == mUseMLModel) {
return;
@@ -885,6 +885,9 @@
private boolean isTrackpadDevice(int deviceId) {
InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+ if (inputDevice == null) {
+ return false;
+ }
return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
| InputDevice.SOURCE_TOUCHPAD);
}
@@ -1133,7 +1136,8 @@
private boolean isButtonPressFromTrackpad(MotionEvent ev) {
// We don't allow back for button press from the trackpad, and yet we do with a mouse.
int sources = InputManager.getInstance().getInputDevice(ev.getDeviceId()).getSources();
- return (sources & (SOURCE_MOUSE | SOURCE_TOUCHPAD)) == sources && ev.getButtonState() != 0;
+ int sourceTrackpad = (SOURCE_MOUSE | SOURCE_TOUCHPAD);
+ return (sources & sourceTrackpad) == sourceTrackpad && ev.getButtonState() != 0;
}
private void dispatchToBackAnimation(MotionEvent event) {
@@ -1230,7 +1234,7 @@
pw.println(" mIsEnabled=" + mIsEnabled);
pw.println(" mIsAttached=" + mIsAttached);
pw.println(" mIsBackGestureAllowed=" + mIsBackGestureAllowed);
- pw.println(" mIsGesturalModeEnabled=" + mIsGesturalModeEnabled);
+ pw.println(" mIsGestureHandlingEnabled=" + mIsGestureHandlingEnabled);
pw.println(" mIsNavBarShownTransiently=" + mIsNavBarShownTransiently);
pw.println(" mGestureBlockingActivityRunning=" + mGestureBlockingActivityRunning);
pw.println(" mAllowGesture=" + mAllowGesture);
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index efbec29..48790c2 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -46,7 +46,6 @@
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
-import com.android.systemui.util.kotlin.getOrNull
import com.android.systemui.util.settings.SecureSettings
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener
@@ -219,7 +218,7 @@
debugLog { "onShowNoteTask - opened as app bubble: $info" }
}
is NoteTaskLaunchMode.Activity -> {
- if (activityManager.isInForeground(info.packageName)) {
+ if (info.isKeyguardLocked && activityManager.isInForeground(info.packageName)) {
// Force note task into background by calling home.
val intent = createHomeIntent()
context.startActivityAsUser(intent, user)
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt
index fae325c..4420002 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt
@@ -25,12 +25,14 @@
* An entry point represents where the note task has ben called from. In rare cases, it may
* represent a "re-entry" (i.e., [APP_CLIPS]).
*/
-enum class
-NoteTaskEntryPoint {
+enum class NoteTaskEntryPoint {
/** @see [LaunchNoteTaskActivity] */
WIDGET_PICKER_SHORTCUT,
+ /** @see [LaunchNoteTaskActivity] */
+ WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE,
+
/** @see [NoteTaskQuickAffordanceConfig] */
QUICK_AFFORDANCE,
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt
index 48a5933..a79057e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt
@@ -22,6 +22,8 @@
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
+import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
+import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
@@ -41,40 +43,45 @@
/** Logs a [NoteTaskInfo] as an **open** [NoteTaskUiEvent], including package name and uid. */
fun logNoteTaskOpened(info: NoteTaskInfo) {
val event =
- when (info.entryPoint) {
- TAIL_BUTTON -> {
- if (info.isKeyguardLocked) {
- NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED
- } else {
- NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
+ when (info.entryPoint) {
+ TAIL_BUTTON -> {
+ if (info.isKeyguardLocked) {
+ NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED
+ } else {
+ NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
+ }
}
+
+ WIDGET_PICKER_SHORTCUT,
+ WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE -> NOTE_OPENED_VIA_SHORTCUT
+
+ QUICK_AFFORDANCE -> NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
+ APP_CLIPS,
+ KEYBOARD_SHORTCUT,
+ null -> return
}
- WIDGET_PICKER_SHORTCUT -> NOTE_OPENED_VIA_SHORTCUT
- QUICK_AFFORDANCE -> NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
- APP_CLIPS -> return
- KEYBOARD_SHORTCUT -> return
- null -> return
- }
uiEventLogger.log(event, info.uid, info.packageName)
}
/** Logs a [NoteTaskInfo] as a **closed** [NoteTaskUiEvent], including package name and uid. */
fun logNoteTaskClosed(info: NoteTaskInfo) {
val event =
- when (info.entryPoint) {
- TAIL_BUTTON -> {
- if (info.isKeyguardLocked) {
- NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED
- } else {
- NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON
+ when (info.entryPoint) {
+ TAIL_BUTTON -> {
+ if (info.isKeyguardLocked) {
+ NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED
+ } else {
+ NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON
+ }
}
+
+ WIDGET_PICKER_SHORTCUT,
+ WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE,
+ QUICK_AFFORDANCE,
+ APP_CLIPS,
+ KEYBOARD_SHORTCUT,
+ null -> return
}
- WIDGET_PICKER_SHORTCUT -> return
- QUICK_AFFORDANCE -> return
- APP_CLIPS -> return
- KEYBOARD_SHORTCUT -> return
- null -> return
- }
uiEventLogger.log(event, info.uid, info.packageName)
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
index a758347..269eb87 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
@@ -16,6 +16,7 @@
package com.android.systemui.notetask
import android.os.UserHandle
+import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
/** Contextual information required to launch a Note Task by [NoteTaskController]. */
data class NoteTaskInfo(
@@ -27,7 +28,7 @@
) {
val launchMode: NoteTaskLaunchMode =
- if (isKeyguardLocked) {
+ if (isKeyguardLocked || entryPoint == WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE) {
NoteTaskLaunchMode.Activity
} else {
NoteTaskLaunchMode.AppBubble
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
index a2ebead..4d30634 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt
@@ -67,7 +67,8 @@
val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
return ShortcutInfo.Builder(context, NoteTaskController.SHORTCUT_ID)
- .setIntent(LaunchNoteTaskActivity.newIntent(context = context))
+ .setIntent(LaunchNoteTaskActivity.createIntent(context))
+ .setActivity(LaunchNoteTaskActivity.createComponent(context))
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setLongLived(true)
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 0ce20cd..f02d362 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -19,6 +19,7 @@
import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
import android.content.Context
+import android.content.Intent
import android.hardware.input.InputSettings
import android.os.Build
import android.os.UserHandle
@@ -42,7 +43,6 @@
import com.android.systemui.notetask.NoteTaskEnabledKey
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskInfoResolver
-import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
import com.android.systemui.stylus.StylusManager
import dagger.Lazy
import java.util.concurrent.Executor
@@ -122,16 +122,18 @@
isEnabled && isDefaultNotesAppSet -> PickerScreenState.Default()
isEnabled -> {
PickerScreenState.Disabled(
- listOf(
+ explanation =
context.getString(
- R.string.keyguard_affordance_enablement_dialog_notes_app_instruction
- )
- ),
- context.getString(
- R.string.keyguard_affordance_enablement_dialog_notes_app_action
- ),
- "${context.packageName}$COMPONENT_NAME_SEPARATOR" +
- "$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE",
+ R.string.notes_app_quick_affordance_unavailable_explanation
+ ),
+ actionText =
+ context.getString(
+ R.string.keyguard_affordance_enablement_dialog_notes_app_action
+ ),
+ actionIntent =
+ Intent(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE).apply {
+ setPackage(context.packageName)
+ },
)
}
else -> PickerScreenState.UnavailableOnDevice
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
index 493330a..d00a79e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
@@ -16,6 +16,7 @@
package com.android.systemui.notetask.shortcut
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -30,18 +31,27 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- controller.showNoteTaskAsUser(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT, user)
+ val entryPoint =
+ if (isInMultiWindowMode) {
+ NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
+ } else {
+ NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
+ }
+ controller.showNoteTaskAsUser(entryPoint, user)
finish()
}
companion object {
/** Creates a new [Intent] set to start [LaunchNoteTaskActivity]. */
- fun newIntent(context: Context): Intent {
- return Intent(context, LaunchNoteTaskActivity::class.java).apply {
+ fun createIntent(context: Context): Intent =
+ Intent(context, LaunchNoteTaskActivity::class.java).apply {
// Intent's action must be set in shortcuts, or an exception will be thrown.
action = Intent.ACTION_CREATE_NOTE
}
- }
+
+ /** Creates a new [ComponentName] for [LaunchNoteTaskActivity]. */
+ fun createComponent(context: Context): ComponentName =
+ ComponentName(context, LaunchNoteTaskActivity::class.java)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 18be0aa..8d3b745 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -775,9 +775,13 @@
NotificationChannel channel,
int modificationType) {
if (channel.isConversation()) {
- updateWidgets(mAppWidgetManager.getAppWidgetIds(
- new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
- ));
+ mBgExecutor.execute(() -> {
+ if (mUserManager.isUserUnlocked(user)) {
+ updateWidgets(mAppWidgetManager.getAppWidgetIds(
+ new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
+ ));
+ }
+ });
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
index b2e04bb..69cb611 100644
--- a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -26,6 +26,8 @@
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
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.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -34,13 +36,18 @@
interface PowerRepository {
/** Whether the device is interactive. Starts with the current state. */
val isInteractive: Flow<Boolean>
+
+ /** Wakes up the device. */
+ fun wakeUp(why: String, @PowerManager.WakeReason wakeReason: Int)
}
@SysUISingleton
class PowerRepositoryImpl
@Inject
constructor(
- manager: PowerManager,
+ private val manager: PowerManager,
+ @Application private val applicationContext: Context,
+ private val systemClock: SystemClock,
dispatcher: BroadcastDispatcher,
) : PowerRepository {
@@ -68,6 +75,14 @@
awaitClose { dispatcher.unregisterReceiver(receiver) }
}
+ override fun wakeUp(why: String, wakeReason: Int) {
+ manager.wakeUp(
+ systemClock.uptimeMillis(),
+ wakeReason,
+ "${applicationContext.packageName}:$why",
+ )
+ }
+
companion object {
private const val TAG = "PowerRepository"
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
index 3f799f7..c13476f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -17,8 +17,12 @@
package com.android.systemui.power.domain.interactor
+import android.os.PowerManager
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.PowerRepository
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -27,8 +31,27 @@
class PowerInteractor
@Inject
constructor(
- repository: PowerRepository,
+ private val repository: PowerRepository,
+ private val falsingCollector: FalsingCollector,
+ private val screenOffAnimationController: ScreenOffAnimationController,
+ private val statusBarStateController: StatusBarStateController,
) {
/** Whether the screen is on or off. */
val isInteractive: Flow<Boolean> = repository.isInteractive
+
+ /**
+ * Wakes up the device if the device was dozing.
+ *
+ * @param why a string explaining why we're waking the device for debugging purposes. Should be
+ * in SCREAMING_SNAKE_CASE.
+ * @param wakeReason the PowerManager-based reason why we're waking the device.
+ */
+ fun wakeUpIfDozing(why: String, @PowerManager.WakeReason wakeReason: Int) {
+ if (
+ statusBarStateController.isDozing && screenOffAnimationController.allowWakeUpIfDozing()
+ ) {
+ repository.wakeUp(why, wakeReason)
+ falsingCollector.onScreenOnFromTouch()
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 79167f2..c3b5db4 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -25,7 +25,7 @@
import android.widget.LinearLayout
import com.android.settingslib.Utils
import com.android.systemui.R
-import com.android.systemui.animation.LaunchableFrameLayout
+import com.android.systemui.animation.view.LaunchableFrameLayout
import com.android.systemui.statusbar.events.BackgroundAnimatableView
class OngoingPrivacyChip @JvmOverloads constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 06e92d9..a2b2a89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -52,7 +52,6 @@
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.ui.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSContainerController;
@@ -755,8 +754,7 @@
// Alpha progress should be linear on lockscreen shade expansion.
return progress;
}
- if (mIsSmallScreen || !mFeatureFlags.isEnabled(
- Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+ if (mIsSmallScreen) {
return ShadeInterpolation.getContentAlpha(progress);
} else {
return mLargeScreenShadeInterpolator.getQsAlpha(progress);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 897b0e7..5d02830 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -65,14 +65,12 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.DisplayTracker;
-import dagger.Lazy;
-
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
-
+import dagger.Lazy;
public class CustomTile extends QSTileImpl<State> implements TileChangeListener {
public static final String PREFIX = "custom(";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index a066242..d7ae575 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -20,6 +20,8 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepository
+import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepositoryImpl
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
@@ -45,6 +47,11 @@
): CurrentTilesInteractor
@Binds
+ abstract fun provideInstalledTilesPackageRepository(
+ impl: InstalledTilesComponentRepositoryImpl
+ ): InstalledTilesComponentRepository
+
+ @Binds
@IntoMap
@ClassKey(PrototypeCoreStartable::class)
abstract fun providePrototypeCoreStartable(startable: PrototypeCoreStartable): CoreStartable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
new file mode 100644
index 0000000..498f403
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.qs.pipeline.data.repository
+
+import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE
+import android.annotation.WorkerThread
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.os.UserHandle
+import android.service.quicksettings.TileService
+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.util.kotlin.isComponentActuallyEnabled
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+
+interface InstalledTilesComponentRepository {
+
+ fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>>
+}
+
+@SysUISingleton
+class InstalledTilesComponentRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ private val packageManager: PackageManager,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : InstalledTilesComponentRepository {
+
+ override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> =
+ conflatedCallbackFlow {
+ val receiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ trySend(Unit)
+ }
+ }
+ applicationContext.registerReceiverAsUser(
+ receiver,
+ UserHandle.of(userId),
+ INTENT_FILTER,
+ /* broadcastPermission = */ null,
+ /* scheduler = */ null
+ )
+
+ awaitClose { applicationContext.unregisterReceiver(receiver) }
+ }
+ .onStart { emit(Unit) }
+ .map { reloadComponents(userId) }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+
+ @WorkerThread
+ private fun reloadComponents(userId: Int): Set<ComponentName> {
+ return packageManager
+ .queryIntentServicesAsUser(INTENT, FLAGS, userId)
+ .mapNotNull { it.serviceInfo }
+ .filter { it.permission == BIND_QUICK_SETTINGS_TILE }
+ .filter { packageManager.isComponentActuallyEnabled(it) }
+ .mapTo(mutableSetOf()) { it.componentName }
+ }
+
+ companion object {
+ private val INTENT_FILTER =
+ IntentFilter().apply {
+ addAction(Intent.ACTION_PACKAGE_ADDED)
+ addAction(Intent.ACTION_PACKAGE_CHANGED)
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_REPLACED)
+ addDataScheme("package")
+ }
+ private val INTENT = Intent(TileService.ACTION_QS_TILE)
+ private val FLAGS =
+ ResolveInfoFlags.of(
+ (PackageManager.GET_SERVICES or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE)
+ .toLong()
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
index 3b2362f..a162d11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
@@ -42,6 +42,8 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
/** Repository that tracks the current tiles. */
@@ -104,6 +106,8 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : TileSpecRepository {
+ private val mutex = Mutex()
+
private val retailModeTiles by lazy {
resources
.getString(R.string.quick_settings_tiles_retail_mode)
@@ -145,37 +149,40 @@
.flowOn(backgroundDispatcher)
}
- override suspend fun addTile(userId: Int, tile: TileSpec, position: Int) {
- if (tile == TileSpec.Invalid) {
- return
- }
- val tilesList = loadTiles(userId).toMutableList()
- if (tile !in tilesList) {
- if (position < 0 || position >= tilesList.size) {
- tilesList.add(tile)
- } else {
- tilesList.add(position, tile)
+ override suspend fun addTile(userId: Int, tile: TileSpec, position: Int) =
+ mutex.withLock {
+ if (tile == TileSpec.Invalid) {
+ return
}
- storeTiles(userId, tilesList)
+ val tilesList = loadTiles(userId).toMutableList()
+ if (tile !in tilesList) {
+ if (position < 0 || position >= tilesList.size) {
+ tilesList.add(tile)
+ } else {
+ tilesList.add(position, tile)
+ }
+ storeTiles(userId, tilesList)
+ }
}
- }
- override suspend fun removeTiles(userId: Int, tiles: Collection<TileSpec>) {
- if (tiles.all { it == TileSpec.Invalid }) {
- return
+ override suspend fun removeTiles(userId: Int, tiles: Collection<TileSpec>) =
+ mutex.withLock {
+ if (tiles.all { it == TileSpec.Invalid }) {
+ return
+ }
+ val tilesList = loadTiles(userId).toMutableList()
+ if (tilesList.removeAll(tiles)) {
+ storeTiles(userId, tilesList.toList())
+ }
}
- val tilesList = loadTiles(userId).toMutableList()
- if (tilesList.removeAll(tiles)) {
- storeTiles(userId, tilesList.toList())
- }
- }
- override suspend fun setTiles(userId: Int, tiles: List<TileSpec>) {
- val filtered = tiles.filter { it != TileSpec.Invalid }
- if (filtered.isNotEmpty()) {
- storeTiles(userId, filtered)
+ override suspend fun setTiles(userId: Int, tiles: List<TileSpec>) =
+ mutex.withLock {
+ val filtered = tiles.filter { it != TileSpec.Invalid }
+ if (filtered.isNotEmpty()) {
+ storeTiles(userId, filtered)
+ }
}
- }
private suspend fun loadTiles(@UserIdInt forUser: Int): List<TileSpec> {
return withContext(backgroundDispatcher) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index c579f5c..ff881f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -36,6 +36,7 @@
import com.android.systemui.qs.external.TileLifecycleManager
import com.android.systemui.qs.external.TileServiceKey
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository
+import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.domain.model.TileModel
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -52,6 +53,8 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
@@ -117,11 +120,13 @@
* * Platform tiles will be kept between users, with a call to [QSTile.userSwitch]
* * [CustomTile]s will only be destroyed if the user changes.
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class CurrentTilesInteractorImpl
@Inject
constructor(
private val tileSpecRepository: TileSpecRepository,
+ private val installedTilesComponentRepository: InstalledTilesComponentRepository,
private val userRepository: UserRepository,
private val customTileStatePersister: CustomTileStatePersister,
private val tileFactory: QSFactory,
@@ -141,7 +146,7 @@
override val currentTiles: StateFlow<List<TileModel>> = _currentSpecsAndTiles.asStateFlow()
// This variable should only be accessed inside the collect of `startTileCollection`.
- private val specsToTiles = mutableMapOf<TileSpec, QSTile>()
+ private val specsToTiles = mutableMapOf<TileSpec, TileOrNotInstalled>()
private val currentUser = MutableStateFlow(userTracker.userId)
override val userId = currentUser.asStateFlow()
@@ -149,6 +154,20 @@
private val _userContext = MutableStateFlow(userTracker.userContext)
override val userContext = _userContext.asStateFlow()
+ private val userAndTiles =
+ currentUser
+ .flatMapLatest { userId ->
+ tileSpecRepository.tilesSpecs(userId).map { UserAndTiles(userId, it) }
+ }
+ .distinctUntilChanged()
+ .pairwise(UserAndTiles(-1, emptyList()))
+ .flowOn(backgroundDispatcher)
+
+ private val installedPackagesWithTiles =
+ currentUser.flatMapLatest {
+ installedTilesComponentRepository.getInstalledTilesComponents(it)
+ }
+
init {
if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
startTileCollection()
@@ -158,68 +177,98 @@
@OptIn(ExperimentalCoroutinesApi::class)
private fun startTileCollection() {
scope.launch {
- userRepository.selectedUserInfo
- .flatMapLatest { user ->
+ launch {
+ userRepository.selectedUserInfo.collect { user ->
currentUser.value = user.id
_userContext.value = userTracker.userContext
- tileSpecRepository.tilesSpecs(user.id).map { user.id to it }
}
- .distinctUntilChanged()
- .pairwise(-1 to emptyList())
- .flowOn(backgroundDispatcher)
- .collect { (old, new) ->
- val newTileList = new.second
- val userChanged = old.first != new.first
- val newUser = new.first
+ }
- // Destroy all tiles that are not in the new set
- specsToTiles
- .filter { it.key !in newTileList }
- .forEach { entry ->
- logger.logTileDestroyed(
- entry.key,
- if (userChanged) {
- QSPipelineLogger.TileDestroyedReason
- .TILE_NOT_PRESENT_IN_NEW_USER
- } else {
- QSPipelineLogger.TileDestroyedReason.TILE_REMOVED
- }
- )
- entry.value.destroy()
- }
- // MutableMap will keep the insertion order
- val newTileMap = mutableMapOf<TileSpec, QSTile>()
+ launch(backgroundDispatcher) {
+ userAndTiles
+ .combine(installedPackagesWithTiles) { usersAndTiles, packages ->
+ Data(
+ usersAndTiles.previousValue,
+ usersAndTiles.newValue,
+ packages,
+ )
+ }
+ .collectLatest {
+ val newTileList = it.newData.tiles
+ val userChanged = it.oldData.userId != it.newData.userId
+ val newUser = it.newData.userId
+ val components = it.installedComponents
- newTileList.forEach { tileSpec ->
- if (tileSpec !in newTileMap) {
- val newTile =
- if (tileSpec in specsToTiles) {
- processExistingTile(
- tileSpec,
- specsToTiles.getValue(tileSpec),
- userChanged,
- newUser
- )
- ?: createTile(tileSpec)
+ // Destroy all tiles that are not in the new set
+ specsToTiles
+ .filter {
+ it.key !in newTileList && it.value is TileOrNotInstalled.Tile
+ }
+ .forEach { entry ->
+ logger.logTileDestroyed(
+ entry.key,
+ if (userChanged) {
+ QSPipelineLogger.TileDestroyedReason
+ .TILE_NOT_PRESENT_IN_NEW_USER
+ } else {
+ QSPipelineLogger.TileDestroyedReason.TILE_REMOVED
+ }
+ )
+ (entry.value as TileOrNotInstalled.Tile).tile.destroy()
+ }
+ // MutableMap will keep the insertion order
+ val newTileMap = mutableMapOf<TileSpec, TileOrNotInstalled>()
+
+ newTileList.forEach { tileSpec ->
+ if (tileSpec !in newTileMap) {
+ if (
+ tileSpec is TileSpec.CustomTileSpec &&
+ tileSpec.componentName !in components
+ ) {
+ newTileMap[tileSpec] = TileOrNotInstalled.NotInstalled
} else {
- createTile(tileSpec)
+ // Create tile here will never try to create a CustomTile that
+ // is not installed
+ val newTile =
+ if (tileSpec in specsToTiles) {
+ processExistingTile(
+ tileSpec,
+ specsToTiles.getValue(tileSpec),
+ userChanged,
+ newUser
+ )
+ ?: createTile(tileSpec)
+ } else {
+ createTile(tileSpec)
+ }
+ if (newTile != null) {
+ newTileMap[tileSpec] = TileOrNotInstalled.Tile(newTile)
+ }
}
- if (newTile != null) {
- newTileMap[tileSpec] = newTile
}
}
- }
- val resolvedSpecs = newTileMap.keys.toList()
- specsToTiles.clear()
- specsToTiles.putAll(newTileMap)
- _currentSpecsAndTiles.value = newTileMap.map { TileModel(it.key, it.value) }
- if (resolvedSpecs != newTileList) {
- // There were some tiles that couldn't be created. Change the value in the
- // repository
- launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) }
+ val resolvedSpecs = newTileMap.keys.toList()
+ specsToTiles.clear()
+ specsToTiles.putAll(newTileMap)
+ _currentSpecsAndTiles.value =
+ newTileMap
+ .filter { it.value is TileOrNotInstalled.Tile }
+ .map {
+ TileModel(it.key, (it.value as TileOrNotInstalled.Tile).tile)
+ }
+ logger.logTilesNotInstalled(
+ newTileMap.filter { it.value is TileOrNotInstalled.NotInstalled }.keys,
+ newUser
+ )
+ if (resolvedSpecs != newTileList) {
+ // There were some tiles that couldn't be created. Change the value in
+ // the
+ // repository
+ launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) }
+ }
}
- }
+ }
}
}
@@ -301,42 +350,66 @@
private fun processExistingTile(
tileSpec: TileSpec,
- qsTile: QSTile,
+ tileOrNotInstalled: TileOrNotInstalled,
userChanged: Boolean,
user: Int,
): QSTile? {
- return when {
- !qsTile.isAvailable -> {
- logger.logTileDestroyed(
- tileSpec,
- QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE
- )
- qsTile.destroy()
- null
- }
- // Tile is in the current list of tiles and available.
- // We have a handful of different cases
- qsTile !is CustomTile -> {
- // The tile is not a custom tile. Make sure they are reset to the correct user
- if (userChanged) {
- qsTile.userSwitch(user)
- logger.logTileUserChanged(tileSpec, user)
+ return when (tileOrNotInstalled) {
+ is TileOrNotInstalled.NotInstalled -> null
+ is TileOrNotInstalled.Tile -> {
+ val qsTile = tileOrNotInstalled.tile
+ when {
+ !qsTile.isAvailable -> {
+ logger.logTileDestroyed(
+ tileSpec,
+ QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE
+ )
+ qsTile.destroy()
+ null
+ }
+ // Tile is in the current list of tiles and available.
+ // We have a handful of different cases
+ qsTile !is CustomTile -> {
+ // The tile is not a custom tile. Make sure they are reset to the correct
+ // user
+ if (userChanged) {
+ qsTile.userSwitch(user)
+ logger.logTileUserChanged(tileSpec, user)
+ }
+ qsTile
+ }
+ qsTile.user == user -> {
+ // The tile is a custom tile for the same user, just return it
+ qsTile
+ }
+ else -> {
+ // The tile is a custom tile and the user has changed. Destroy it
+ qsTile.destroy()
+ logger.logTileDestroyed(
+ tileSpec,
+ QSPipelineLogger.TileDestroyedReason.CUSTOM_TILE_USER_CHANGED
+ )
+ null
+ }
}
- qsTile
- }
- qsTile.user == user -> {
- // The tile is a custom tile for the same user, just return it
- qsTile
- }
- else -> {
- // The tile is a custom tile and the user has changed. Destroy it
- qsTile.destroy()
- logger.logTileDestroyed(
- tileSpec,
- QSPipelineLogger.TileDestroyedReason.CUSTOM_TILE_USER_CHANGED
- )
- null
}
}
}
+
+ private sealed interface TileOrNotInstalled {
+ object NotInstalled : TileOrNotInstalled
+
+ @JvmInline value class Tile(val tile: QSTile) : TileOrNotInstalled
+ }
+
+ private data class UserAndTiles(
+ val userId: Int,
+ val tiles: List<TileSpec>,
+ )
+
+ private data class Data(
+ val oldData: UserAndTiles,
+ val newData: UserAndTiles,
+ val installedComponents: Set<ComponentName>,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index ff7d206..8318ec9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -124,6 +124,18 @@
tileListLogBuffer.log(TILE_LIST_TAG, LogLevel.DEBUG, {}, { "Using retail tiles" })
}
+ fun logTilesNotInstalled(tiles: Collection<TileSpec>, user: Int) {
+ tileListLogBuffer.log(
+ TILE_LIST_TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = tiles.toString()
+ int1 = user
+ },
+ { "Tiles kept for not installed packages for user $int1: $str1" }
+ )
+ }
+
/** Reasons for destroying an existing tile. */
enum class TileDestroyedReason(val readable: String) {
TILE_REMOVED("Tile removed from current set"),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index eef4c1d..b5e6a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -166,17 +166,6 @@
}
@Override
- protected void handleLongClick(@Nullable View view) {
- try {
- // Need to wake on long click so bouncer->settings works.
- mDreamManager.awaken();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Can't awaken", e);
- }
- super.handleLongClick(view);
- }
-
- @Override
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = getTileLabel();
state.secondaryLabel = getActiveDreamName();
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
index 3e78489..9962c91 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -16,10 +16,6 @@
package com.android.systemui.screenrecord;
-import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
-import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
-import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
-
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
@@ -40,9 +36,6 @@
private LinearLayout mSelectedMic;
private LinearLayout mSelectedInternal;
private LinearLayout mSelectedMicAndInternal;
- private LinearLayout mMicOption;
- private LinearLayout mMicAndInternalOption;
- private LinearLayout mInternalOption;
public ScreenRecordingAdapter(Context context, int resource,
List<ScreenRecordingAudioSource> objects) {
@@ -54,28 +47,21 @@
mSelectedInternal = getSelected(R.string.screenrecord_device_audio_label);
mSelectedMic = getSelected(R.string.screenrecord_mic_label);
mSelectedMicAndInternal = getSelected(R.string.screenrecord_device_audio_and_mic_label);
-
- mMicOption = getOption(R.string.screenrecord_mic_label, Resources.ID_NULL);
- mMicOption.removeViewAt(1);
-
- mMicAndInternalOption = getOption(
- R.string.screenrecord_device_audio_and_mic_label, Resources.ID_NULL);
- mMicAndInternalOption.removeViewAt(1);
-
- mInternalOption = getOption(R.string.screenrecord_device_audio_label,
- R.string.screenrecord_device_audio_description);
}
private LinearLayout getOption(int label, int description) {
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = LayoutInflater.from(getContext());
LinearLayout layout = (LinearLayout) inflater
.inflate(R.layout.screen_record_dialog_audio_source, null, false);
((TextView) layout.findViewById(R.id.screen_recording_dialog_source_text))
.setText(label);
- if (description != Resources.ID_NULL)
- ((TextView) layout.findViewById(R.id.screen_recording_dialog_source_description))
- .setText(description);
+ TextView descriptionView = layout.findViewById(
+ R.id.screen_recording_dialog_source_description);
+ if (description != Resources.ID_NULL) {
+ descriptionView.setText(description);
+ } else {
+ descriptionView.setVisibility(View.GONE);
+ }
return layout;
}
@@ -92,11 +78,13 @@
public View getDropDownView(int position, View convertView, ViewGroup parent) {
switch (getItem(position)) {
case INTERNAL:
- return mInternalOption;
+ return getOption(R.string.screenrecord_device_audio_label,
+ R.string.screenrecord_device_audio_description);
case MIC_AND_INTERNAL:
- return mMicAndInternalOption;
+ return getOption(
+ R.string.screenrecord_device_audio_and_mic_label, Resources.ID_NULL);
case MIC:
- return mMicOption;
+ return getOption(R.string.screenrecord_mic_label, Resources.ID_NULL);
default:
return super.getDropDownView(position, convertView, parent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 452fc39..6d00a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -126,12 +126,12 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.shared.model.WakefulnessModel;
@@ -1659,10 +1659,9 @@
Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
mKeyguardNotificationBottomPadding = bottomPadding;
- float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
- // getMinStackScrollerPadding is from the top of the screen,
- // but we need it from the top of the NSSL.
- - mNotificationStackScrollLayoutController.getTop();
+ float staticTopPadding = mClockPositionAlgorithm.getLockscreenNotifPadding(
+ mNotificationStackScrollLayoutController.getTop());
+
mKeyguardNotificationTopPadding = staticTopPadding;
// To debug the available space, enable debug lines in this class. If you change how the
@@ -1676,8 +1675,8 @@
Log.i(TAG, "\n");
Log.i(TAG, "staticTopPadding[" + staticTopPadding
+ "] = Clock.padding["
- + mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
- + "] - NSSLC.top[" + mNotificationStackScrollLayoutController.getTop()
+ + mClockPositionAlgorithm.getLockscreenNotifPadding(
+ mNotificationStackScrollLayoutController.getTop())
+ "]"
);
Log.i(TAG, "bottomPadding[" + bottomPadding
@@ -2440,6 +2439,7 @@
boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
if (mPanelExpanded != isExpanded) {
mPanelExpanded = isExpanded;
+ updateSystemUiStateFlags();
mShadeExpansionStateManager.onShadeExpansionFullyChanged(isExpanded);
if (!isExpanded) {
mQsController.closeQsCustomizer();
@@ -2447,6 +2447,7 @@
}
}
+ @Override
public boolean isPanelExpanded() {
return mPanelExpanded;
}
@@ -2904,9 +2905,7 @@
float scrimMinFraction;
if (mSplitShadeEnabled) {
boolean highHun = mHeadsUpStartHeight * 2.5
- >
- (mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)
- ? mSplitShadeFullTransitionDistance : mSplitShadeScrimTransitionDistance);
+ > mSplitShadeFullTransitionDistance;
// if HUN height is higher than 40% of predefined transition distance, it means HUN
// is too high for regular transition. In that case we need to calculate transition
// distance - here we take scrim transition distance as equal to shade transition
@@ -3440,9 +3439,8 @@
Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
+ isFullyExpanded() + " inQs=" + mQsController.getExpanded());
}
- boolean isPanelVisible = mCentralSurfaces != null && mCentralSurfaces.isPanelExpanded();
mSysUiState
- .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, isPanelVisible)
+ .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, mPanelExpanded)
.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 f4485c9..c4b74fc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -46,12 +46,12 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
+import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
+import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.log.BouncerLogger;
import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 81fe3ca..fba0120 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -27,6 +27,7 @@
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.fragments.FragmentService
import com.android.systemui.navigationbar.NavigationModeController
@@ -45,6 +46,7 @@
@VisibleForTesting
internal const val INSET_DEBOUNCE_MILLIS = 500L
+@SysUISingleton
class NotificationsQSContainerController @Inject constructor(
view: NotificationsQuickSettingsContainer,
private val navigationModeController: NavigationModeController,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index fd82e2f..9b797a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -18,7 +18,6 @@
import android.hardware.display.AmbientDisplayConfiguration
import android.os.PowerManager
-import android.os.SystemClock
import android.provider.Settings
import android.view.GestureDetector
import android.view.MotionEvent
@@ -28,8 +27,8 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
@@ -50,7 +49,7 @@
private val notificationShadeWindowView: NotificationShadeWindowView,
private val falsingManager: FalsingManager,
private val dockManager: DockManager,
- private val centralSurfaces: CentralSurfaces,
+ private val powerInteractor: PowerInteractor,
private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
private val statusBarStateController: StatusBarStateController,
private val shadeLogger: ShadeLogger,
@@ -88,11 +87,7 @@
shadeLogger.logSingleTapUpFalsingState(proximityIsNotNear, isNotAFalseTap)
if (proximityIsNotNear && isNotAFalseTap) {
shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing")
- centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(),
- "PULSING_SINGLE_TAP",
- PowerManager.WAKE_REASON_TAP
- )
+ powerInteractor.wakeUpIfDozing("PULSING_SINGLE_TAP", PowerManager.WAKE_REASON_TAP)
}
return true
}
@@ -113,11 +108,7 @@
!falsingManager.isProximityNear &&
!falsingManager.isFalseDoubleTap
) {
- centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(),
- "PULSING_DOUBLE_TAP",
- PowerManager.WAKE_REASON_TAP
- )
+ powerInteractor.wakeUpIfDozing("PULSING_DOUBLE_TAP", PowerManager.WAKE_REASON_TAP)
return true
}
return false
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 29c4acc..9ed0e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -71,6 +71,9 @@
/** Posts a request to expand the shade to quick settings. */
void postAnimateExpandQs();
+ /** Cancels any ongoing expansion touch handling and collapses the shade. */
+ void cancelExpansionAndCollapseShade();
+
/**
* If the shade is not fully expanded, collapse it animated.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 7942b58..c9338b3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -270,6 +270,17 @@
}
@Override
+ public void cancelExpansionAndCollapseShade() {
+ if (mNotificationPanelViewController.isTracking()) {
+ mNotificationShadeWindowViewController.cancelCurrentTouch();
+ }
+ if (mNotificationPanelViewController.isPanelExpanded()
+ && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+ animateCollapseShade();
+ }
+ }
+
+ @Override
public void collapseOnMainThread() {
if (Looper.getMainLooper().isCurrentThread()) {
collapseShade();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index f080d3d..3af75ce 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -34,6 +34,7 @@
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.motion.widget.MotionLayout
+import androidx.core.view.doOnLayout
import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
@@ -220,6 +221,7 @@
override fun demoCommands() = listOf(DemoMode.COMMAND_CLOCK)
override fun dispatchDemoCommand(command: String, args: Bundle) =
clock.dispatchDemoCommand(command, args)
+
override fun onDemoModeStarted() = clock.onDemoModeStarted()
override fun onDemoModeFinished() = clock.onDemoModeFinished()
}
@@ -259,6 +261,7 @@
resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height)
lastInsets?.let { updateConstraintsForInsets(header, it) }
updateResources()
+ updateCarrierGroupPadding()
}
}
@@ -291,6 +294,7 @@
privacyIconsController.chipVisibilityListener = chipVisibilityListener
updateVisibility()
updateTransition()
+ updateCarrierGroupPadding()
header.setOnApplyWindowInsetsListener(insetListener)
@@ -298,8 +302,6 @@
val newPivot = if (v.isLayoutRtl) v.width.toFloat() else 0f
v.pivotX = newPivot
v.pivotY = v.height.toFloat() / 2
-
- mShadeCarrierGroup.setPaddingRelative((v.width * v.scaleX).toInt(), 0, 0, 0)
}
clock.setOnClickListener { launchClockActivity() }
@@ -359,6 +361,14 @@
.load(context, resources.getXml(R.xml.large_screen_shade_header))
}
+ private fun updateCarrierGroupPadding() {
+ clock.doOnLayout {
+ val maxClockWidth =
+ (clock.width * resources.getFloat(R.dimen.qqs_expand_clock_scale)).toInt()
+ mShadeCarrierGroup.setPaddingRelative(maxClockWidth, 0, 0, 0)
+ }
+ }
+
private fun updateConstraintsForInsets(view: MotionLayout, insets: WindowInsets) {
val cutout = insets.displayCutout.also { this.cutout = it }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 1752ff6..4b2a65f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -37,6 +37,10 @@
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.LightRevealScrim
+import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.NotificationShelfController
+import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent
+import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.TapAgainView
@@ -49,6 +53,7 @@
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import javax.inject.Named
+import javax.inject.Provider
/** Module for classes related to the notification shade. */
@Module
@@ -102,6 +107,32 @@
return notificationShadeWindowView.findViewById(R.id.notification_stack_scroller)
}
+ @Provides
+ @SysUISingleton
+ fun providesNotificationShelfController(
+ featureFlags: FeatureFlags,
+ newImpl: Provider<NotificationShelfViewBinderWrapperControllerImpl>,
+ notificationShelfComponentBuilder: NotificationShelfComponent.Builder,
+ layoutInflater: LayoutInflater,
+ notificationStackScrollLayout: NotificationStackScrollLayout,
+ ): NotificationShelfController {
+ return if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+ newImpl.get()
+ } else {
+ val shelfView =
+ layoutInflater.inflate(
+ R.layout.status_bar_notification_shelf,
+ notificationStackScrollLayout,
+ false
+ ) as NotificationShelf
+ val component =
+ notificationShelfComponentBuilder.notificationShelf(shelfView).build()
+ val notificationShelfController = component.notificationShelfController
+ notificationShelfController.init()
+ notificationShelfController
+ }
+ }
+
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@Provides
@SysUISingleton
@@ -157,6 +188,15 @@
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@Provides
@SysUISingleton
+ fun providesNotificationsQuickSettingsContainer(
+ notificationShadeWindowView: NotificationShadeWindowView,
+ ): NotificationsQuickSettingsContainer {
+ return notificationShadeWindowView.findViewById(R.id.notification_container_parent)
+ }
+
+ // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
+ @Provides
+ @SysUISingleton
@Named(SHADE_HEADER)
fun providesShadeHeaderView(
notificationShadeWindowView: NotificationShadeWindowView,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 0548180..9c80e02 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -60,7 +60,7 @@
* Returns whether the shade height is greater than zero or the shade is expecting a synthesized
* down event.
*/
- @get:Deprecated("use {@link #isExpanded()} instead") val isPanelExpanded: Boolean
+ val isPanelExpanded: Boolean
/** Returns whether the shade is fully expanded in either QS or QQS. */
val isShadeFullyExpanded: Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index 4e1c272..abb69f6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -16,24 +16,11 @@
package com.android.systemui.shade.transition
-import android.content.res.Configuration
-import android.content.res.Resources
-import android.util.MathUtils.constrain
-import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.shade.PanelState
-import com.android.systemui.shade.STATE_OPENING
import com.android.systemui.shade.ShadeExpansionChangeEvent
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.util.LargeScreenUtils
import java.io.PrintWriter
import javax.inject.Inject
@@ -42,37 +29,19 @@
class ScrimShadeTransitionController
@Inject
constructor(
- configurationController: ConfigurationController,
dumpManager: DumpManager,
private val scrimController: ScrimController,
- @Main private val resources: Resources,
- private val statusBarStateController: SysuiStatusBarStateController,
- private val headsUpManager: HeadsUpManager,
- private val featureFlags: FeatureFlags,
) {
- private var inSplitShade = false
- private var splitShadeScrimTransitionDistance = 0
private var lastExpansionFraction: Float? = null
private var lastExpansionEvent: ShadeExpansionChangeEvent? = null
private var currentPanelState: Int? = null
init {
- updateResources()
- configurationController.addCallback(
- object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration?) {
- updateResources()
- }
- })
dumpManager.registerDumpable(
- ScrimShadeTransitionController::class.java.simpleName, this::dump)
- }
-
- private fun updateResources() {
- inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources)
- splitShadeScrimTransitionDistance =
- resources.getDimensionPixelSize(R.dimen.split_shade_scrim_transition_distance)
+ ScrimShadeTransitionController::class.java.simpleName,
+ this::dump
+ )
}
fun onPanelStateChanged(@PanelState state: Int) {
@@ -87,46 +56,25 @@
private fun onStateChanged() {
val expansionEvent = lastExpansionEvent ?: return
- val panelState = currentPanelState
- val expansionFraction = calculateScrimExpansionFraction(expansionEvent, panelState)
+ val expansionFraction = calculateScrimExpansionFraction(expansionEvent)
scrimController.setRawPanelExpansionFraction(expansionFraction)
lastExpansionFraction = expansionFraction
}
- private fun calculateScrimExpansionFraction(
- expansionEvent: ShadeExpansionChangeEvent,
- @PanelState panelState: Int?
- ): Float {
- return if (canUseCustomFraction(panelState)) {
- constrain(expansionEvent.dragDownPxAmount / splitShadeScrimTransitionDistance, 0f, 1f)
- } else {
- expansionEvent.fraction
- }
+ private fun calculateScrimExpansionFraction(expansionEvent: ShadeExpansionChangeEvent): Float {
+ return expansionEvent.fraction
}
- private fun canUseCustomFraction(panelState: Int?) =
- inSplitShade && isScreenUnlocked() && panelState == STATE_OPENING &&
- // in case of HUN we can't always use predefined distances to manage scrim
- // transition because dragDownPxAmount can start from value bigger than
- // splitShadeScrimTransitionDistance
- !headsUpManager.isTrackingHeadsUp &&
- !featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)
-
- private fun isScreenUnlocked() =
- statusBarStateController.currentOrUpcomingState == StatusBarState.SHADE
-
private fun dump(printWriter: PrintWriter, args: Array<String>) {
printWriter.println(
"""
ScrimShadeTransitionController:
- Resources:
- inSplitShade: $inSplitShade
- isScreenUnlocked: ${isScreenUnlocked()}
- splitShadeScrimTransitionDistance: $splitShadeScrimTransitionDistance
State:
currentPanelState: $currentPanelState
lastExpansionFraction: $lastExpansionFraction
lastExpansionEvent: $lastExpansionEvent
- """.trimIndent())
+ """
+ .trimIndent()
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 558dd30..faffb3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -329,8 +329,8 @@
}
public void reset() {
- mEntry = null;
removeAutoRemovalCallbacks("reset()");
+ mEntry = null;
mRemoveAlertRunnable = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index f409f80..926d9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -94,8 +94,8 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.log.LogLevel;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1c9bc60..5dcf6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -43,6 +43,11 @@
void onUserSwitched(int newUserId);
/**
+ * Called when a new row is created and bound to a notification.
+ */
+ void onBindRow(ExpandableNotificationRow row);
+
+ /**
* @return true iff the device is in vr mode
*/
boolean isDeviceInVrMode();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 9d7f3be..edf37ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -40,8 +40,6 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
import com.android.systemui.animation.ShadeInterpolation;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -226,9 +224,7 @@
if (ambientState.isBouncerInTransit()) {
viewState.setAlpha(aboutToShowBouncerProgress(expansion));
} else {
- FeatureFlags flags = ambientState.getFeatureFlags();
- if (ambientState.isSmallScreen() || !flags.isEnabled(
- Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+ if (ambientState.isSmallScreen()) {
viewState.setAlpha(ShadeInterpolation.getContentAlpha(expansion));
} else {
LargeScreenShadeInterpolator interpolator =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f6c9a5c..73eba0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -35,7 +35,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8aeefee..b116246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -274,10 +274,6 @@
Assert.isMainThread();
checkForReentrantCall();
- // TODO (b/206842750): This method is called from (silent) clear all and non-clear all
- // contexts and should be checking the NO_CLEAR flag, rather than depending on NSSL
- // to pass in a properly filtered list of notifications
-
final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>();
for (int i = 0; i < entriesToDismiss.size(); i++) {
NotificationEntry entry = entriesToDismiss.get(i).first;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 23b5241..314566e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -633,12 +633,17 @@
mFSIUpdateCandidates.removeAll(toRemoveForFSI)
}
- /** When an action is pressed on a notification, end HeadsUp lifetime extension. */
+ /**
+ * When an action is pressed on a notification, make sure we don't lifetime-extend it in the
+ * future by informing the HeadsUpManager, and make sure we don't keep lifetime-extending it if
+ * we already are.
+ *
+ * @see HeadsUpManager.setUserActionMayIndirectlyRemove
+ * @see HeadsUpManager.canRemoveImmediately
+ */
private val mActionPressListener = Consumer<NotificationEntry> { entry ->
- if (mNotifsExtendingLifetime.contains(entry)) {
- val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key)
- mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis)
- }
+ mHeadsUpManager.setUserActionMayIndirectlyRemove(entry)
+ mExecutor.execute { endNotifLifetimeExtensionIfExtended(entry) }
}
private val mLifetimeExtender = object : NotifLifetimeExtender {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 706594c..2fa070c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -28,9 +28,12 @@
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
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.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.expansionChanges
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
@@ -47,29 +50,30 @@
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import java.io.PrintWriter
import javax.inject.Inject
+import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emitAll
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
- * headers on the lockscreen. If enabled, it will also track and hide seen notifications on the
- * lockscreen.
+ * headers on the lockscreen.
*/
@CoordinatorScope
class KeyguardCoordinator
@@ -82,6 +86,7 @@
private val keyguardRepository: KeyguardRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val logger: KeyguardCoordinatorLogger,
+ private val notifPipelineFlags: NotifPipelineFlags,
@Application private val scope: CoroutineScope,
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
private val secureSettings: SecureSettings,
@@ -90,8 +95,6 @@
) : Coordinator, Dumpable {
private val unseenNotifications = mutableSetOf<NotificationEntry>()
- private val unseenEntryAdded = MutableSharedFlow<NotificationEntry>(extraBufferCapacity = 1)
- private val unseenEntryRemoved = MutableSharedFlow<NotificationEntry>(extraBufferCapacity = 1)
private var unseenFilterEnabled = false
override fun attach(pipeline: NotifPipeline) {
@@ -106,131 +109,79 @@
private fun attachUnseenFilter(pipeline: NotifPipeline) {
pipeline.addFinalizeFilter(unseenNotifFilter)
pipeline.addCollectionListener(collectionListener)
- scope.launch { trackSeenNotifications() }
+ scope.launch { trackUnseenNotificationsWhileUnlocked() }
scope.launch { invalidateWhenUnseenSettingChanges() }
dumpManager.registerDumpable(this)
}
- private suspend fun trackSeenNotifications() {
- // Whether or not keyguard is visible (or occluded).
- val isKeyguardPresent: Flow<Boolean> =
- keyguardTransitionRepository.transitions
- .map { step -> step.to != KeyguardState.GONE }
+ private suspend fun trackUnseenNotificationsWhileUnlocked() {
+ // Whether or not we're actively tracking unseen notifications to mark them as seen when
+ // appropriate.
+ val isTrackingUnseen: Flow<Boolean> =
+ keyguardRepository.isKeyguardShowing
+ // transformLatest so that we can cancel listening to keyguard transitions once
+ // isKeyguardShowing changes (after a successful transition to the keyguard).
+ .transformLatest { isShowing ->
+ if (isShowing) {
+ // If the keyguard is showing, we're not tracking unseen.
+ emit(false)
+ } else {
+ // If the keyguard stops showing, then start tracking unseen notifications.
+ emit(true)
+ // If the screen is turning off, stop tracking, but if that transition is
+ // cancelled, then start again.
+ emitAll(
+ keyguardTransitionRepository.transitions.map { step ->
+ !step.isScreenTurningOff
+ }
+ )
+ }
+ }
+ // Prevent double emit of `false` caused by transition to AOD, followed by keyguard
+ // showing
.distinctUntilChanged()
.onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
- // Separately track seen notifications while the device is locked, applying once the device
- // is unlocked.
- val notificationsSeenWhileLocked = mutableSetOf<NotificationEntry>()
-
- // Use [collectLatest] to cancel any running jobs when [trackingUnseen] changes.
- isKeyguardPresent.collectLatest { isKeyguardPresent: Boolean ->
- if (isKeyguardPresent) {
- // Keyguard is not gone, notifications need to be visible for a certain threshold
- // before being marked as seen
- trackSeenNotificationsWhileLocked(notificationsSeenWhileLocked)
+ // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
+ // showing again
+ var clearUnseenOnBeginTracking = false
+ isTrackingUnseen.collectLatest { trackingUnseen ->
+ if (!trackingUnseen) {
+ // Wait for the user to spend enough time on the lock screen before clearing unseen
+ // set when unlocked
+ awaitTimeSpentNotDozing(SEEN_TIMEOUT)
+ clearUnseenOnBeginTracking = true
+ logger.logSeenOnLockscreen()
} else {
- // Mark all seen-while-locked notifications as seen for real.
- if (notificationsSeenWhileLocked.isNotEmpty()) {
- unseenNotifications.removeAll(notificationsSeenWhileLocked)
- logger.logAllMarkedSeenOnUnlock(
- seenCount = notificationsSeenWhileLocked.size,
- remainingUnseenCount = unseenNotifications.size
- )
- notificationsSeenWhileLocked.clear()
+ if (clearUnseenOnBeginTracking) {
+ clearUnseenOnBeginTracking = false
+ logger.logAllMarkedSeenOnUnlock()
+ unseenNotifications.clear()
}
unseenNotifFilter.invalidateList("keyguard no longer showing")
- // Keyguard is gone, notifications can be immediately marked as seen when they
- // become visible.
- trackSeenNotificationsWhileUnlocked()
+ trackUnseenNotifications()
}
}
}
- /**
- * Keep [notificationsSeenWhileLocked] updated to represent which notifications have actually
- * been "seen" while the device is on the keyguard.
- */
- private suspend fun trackSeenNotificationsWhileLocked(
- notificationsSeenWhileLocked: MutableSet<NotificationEntry>,
- ) = coroutineScope {
- // Remove removed notifications from the set
- launch {
- unseenEntryRemoved.collect { entry ->
- if (notificationsSeenWhileLocked.remove(entry)) {
- logger.logRemoveSeenOnLockscreen(entry)
+ private suspend fun awaitTimeSpentNotDozing(duration: Duration) {
+ keyguardRepository.isDozing
+ // Use transformLatest so that the timeout delay is cancelled if the device enters doze,
+ // and is restarted when doze ends.
+ .transformLatest { isDozing ->
+ if (!isDozing) {
+ delay(duration)
+ // Signal timeout has completed
+ emit(Unit)
}
}
- }
- // Use collectLatest so that the timeout delay is cancelled if the device enters doze, and
- // is restarted when doze ends.
- keyguardRepository.isDozing.collectLatest { isDozing ->
- if (!isDozing) {
- trackSeenNotificationsWhileLockedAndNotDozing(notificationsSeenWhileLocked)
- }
- }
+ // Suspend until the first emission
+ .first()
}
- /**
- * Keep [notificationsSeenWhileLocked] updated to represent which notifications have actually
- * been "seen" while the device is on the keyguard and not dozing. Any new and existing unseen
- * notifications are not marked as seen until they are visible for the [SEEN_TIMEOUT] duration.
- */
- private suspend fun trackSeenNotificationsWhileLockedAndNotDozing(
- notificationsSeenWhileLocked: MutableSet<NotificationEntry>
- ) = coroutineScope {
- // All child tracking jobs will be cancelled automatically when this is cancelled.
- val trackingJobsByEntry = mutableMapOf<NotificationEntry, Job>()
-
- /**
- * Wait for the user to spend enough time on the lock screen before removing notification
- * from unseen set upon unlock.
- */
- suspend fun trackSeenDurationThreshold(entry: NotificationEntry) {
- if (notificationsSeenWhileLocked.remove(entry)) {
- logger.logResetSeenOnLockscreen(entry)
- }
- delay(SEEN_TIMEOUT)
- notificationsSeenWhileLocked.add(entry)
- trackingJobsByEntry.remove(entry)
- logger.logSeenOnLockscreen(entry)
- }
-
- /** Stop any unseen tracking when a notification is removed. */
- suspend fun stopTrackingRemovedNotifs(): Nothing =
- unseenEntryRemoved.collect { entry ->
- trackingJobsByEntry.remove(entry)?.let {
- it.cancel()
- logger.logStopTrackingLockscreenSeenDuration(entry)
- }
- }
-
- /** Start tracking new notifications when they are posted. */
- suspend fun trackNewUnseenNotifs(): Nothing = coroutineScope {
- unseenEntryAdded.collect { entry ->
- logger.logTrackingLockscreenSeenDuration(entry)
- // If this is an update, reset the tracking.
- trackingJobsByEntry[entry]?.let {
- it.cancel()
- logger.logResetSeenOnLockscreen(entry)
- }
- trackingJobsByEntry[entry] = launch { trackSeenDurationThreshold(entry) }
- }
- }
-
- // Start tracking for all notifications that are currently unseen.
- logger.logTrackingLockscreenSeenDuration(unseenNotifications)
- unseenNotifications.forEach { entry ->
- trackingJobsByEntry[entry] = launch { trackSeenDurationThreshold(entry) }
- }
-
- launch { trackNewUnseenNotifs() }
- launch { stopTrackingRemovedNotifs() }
- }
-
- // Track "seen" notifications, marking them as such when either shade is expanded or the
+ // Track "unseen" notifications, marking them as seen when either shade is expanded or the
// notification becomes heads up.
- private suspend fun trackSeenNotificationsWhileUnlocked() {
+ private suspend fun trackUnseenNotifications() {
coroutineScope {
launch { clearUnseenNotificationsWhenShadeIsExpanded() }
launch { markHeadsUpNotificationsAsSeen() }
@@ -299,7 +250,6 @@
) {
logger.logUnseenAdded(entry.key)
unseenNotifications.add(entry)
- unseenEntryAdded.tryEmit(entry)
}
}
@@ -309,14 +259,12 @@
) {
logger.logUnseenUpdated(entry.key)
unseenNotifications.add(entry)
- unseenEntryAdded.tryEmit(entry)
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
if (unseenNotifications.remove(entry)) {
logger.logUnseenRemoved(entry.key)
- unseenEntryRemoved.tryEmit(entry)
}
}
}
@@ -399,3 +347,6 @@
private val SEEN_TIMEOUT = 5.seconds
}
}
+
+private val TransitionStep.isScreenTurningOff: Boolean
+ get() = transitionState == TransitionState.STARTED && to != KeyguardState.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
index c612816..1f8ec34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -19,7 +19,6 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.UnseenNotificationLog
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
private const val TAG = "KeyguardCoordinator"
@@ -29,14 +28,11 @@
constructor(
@UnseenNotificationLog private val buffer: LogBuffer,
) {
- fun logSeenOnLockscreen(entry: NotificationEntry) =
+ fun logSeenOnLockscreen() =
buffer.log(
TAG,
LogLevel.DEBUG,
- messageInitializer = { str1 = entry.key },
- messagePrinter = {
- "Notification [$str1] on lockscreen will be marked as seen when unlocked."
- },
+ "Notifications on lockscreen will be marked as seen when unlocked."
)
fun logTrackingUnseen(trackingUnseen: Boolean) =
@@ -47,21 +43,11 @@
messagePrinter = { "${if (bool1) "Start" else "Stop"} tracking unseen notifications." },
)
- fun logAllMarkedSeenOnUnlock(
- seenCount: Int,
- remainingUnseenCount: Int,
- ) =
+ fun logAllMarkedSeenOnUnlock() =
buffer.log(
TAG,
LogLevel.DEBUG,
- messageInitializer = {
- int1 = seenCount
- int2 = remainingUnseenCount
- },
- messagePrinter = {
- "$int1 Notifications have been marked as seen now that device is unlocked. " +
- "$int2 notifications remain unseen."
- },
+ "Notifications have been marked as seen now that device is unlocked."
)
fun logShadeExpanded() =
@@ -110,60 +96,4 @@
messageInitializer = { str1 = key },
messagePrinter = { "Unseen notif has become heads up: $str1" },
)
-
- fun logTrackingLockscreenSeenDuration(unseenNotifications: Set<NotificationEntry>) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- messageInitializer = {
- str1 = unseenNotifications.joinToString { it.key }
- int1 = unseenNotifications.size
- },
- messagePrinter = {
- "Tracking $int1 unseen notifications for lockscreen seen duration threshold: $str1"
- },
- )
- }
-
- fun logTrackingLockscreenSeenDuration(entry: NotificationEntry) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- messageInitializer = { str1 = entry.key },
- messagePrinter = {
- "Tracking new notification for lockscreen seen duration threshold: $str1"
- },
- )
- }
-
- fun logStopTrackingLockscreenSeenDuration(entry: NotificationEntry) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- messageInitializer = { str1 = entry.key },
- messagePrinter = {
- "Stop tracking removed notification for lockscreen seen duration threshold: $str1"
- },
- )
- }
-
- fun logResetSeenOnLockscreen(entry: NotificationEntry) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- messageInitializer = { str1 = entry.key },
- messagePrinter = {
- "Reset tracking updated notification for lockscreen seen duration threshold: $str1"
- },
- )
- }
-
- fun logRemoveSeenOnLockscreen(entry: NotificationEntry) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- messageInitializer = { str1 = entry.key },
- messagePrinter = { "Notification marked as seen on lockscreen removed: $str1" },
- )
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index bdb206b..38c3723 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -71,7 +71,6 @@
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
- private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
private FeatureFlags mFeatureFlags;
@@ -103,11 +102,9 @@
* Sets up late-bound dependencies for this component.
*/
public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationListContainer listContainer,
- BindRowCallback bindRowCallback) {
+ NotificationListContainer listContainer) {
mPresenter = presenter;
mListContainer = listContainer;
- mBindRowCallback = bindRowCallback;
mIconManager.attach();
}
@@ -179,7 +176,7 @@
mNotificationRemoteInputManager.bindRow(row);
entry.setRow(row);
mNotifBindPipeline.manageRow(entry, row);
- mBindRowCallback.onBindRow(row);
+ mPresenter.onBindRow(row);
row.setInlineReplyAnimationFlagEnabled(
mFeatureFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION));
}
@@ -235,12 +232,4 @@
}
});
}
-
- /** Callback for when a row is bound to an entry. */
- public interface BindRowCallback {
- /**
- * Called when a new row is created and bound to a notification.
- */
- void onBindRow(ExpandableNotificationRow row);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index a5278c3d..c9ebed1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -20,7 +20,6 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.NotificationActivityStarter
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -38,7 +37,6 @@
listContainer: NotificationListContainer,
stackController: NotifStackController,
notificationActivityStarter: NotificationActivityStarter,
- bindRowCallback: NotificationRowBinderImpl.BindRowCallback
)
fun resetUserExpandedStates()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 0ed4175..6409635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -83,7 +83,6 @@
listContainer: NotificationListContainer,
stackController: NotifStackController,
notificationActivityStarter: NotificationActivityStarter,
- bindRowCallback: NotificationRowBinderImpl.BindRowCallback
) {
notificationListener.registerAsSystemService()
@@ -97,10 +96,7 @@
clickerBuilder.build(
Optional.ofNullable(centralSurfaces), bubblesOptional,
notificationActivityStarter))
- notificationRowBinder.setUpWithPresenter(
- presenter,
- listContainer,
- bindRowCallback)
+ notificationRowBinder.setUpWithPresenter(presenter, listContainer)
headsUpViewBinder.setPresenter(presenter)
notifBindPipelineInitializer.initialize()
animatedImageNotificationManager.bind()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 14856da..302a1f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -21,7 +21,6 @@
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.NotificationActivityStarter
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.render.NotifStackController
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -40,7 +39,6 @@
listContainer: NotificationListContainer,
stackController: NotifStackController,
notificationActivityStarter: NotificationActivityStarter,
- bindRowCallback: NotificationRowBinderImpl.BindRowCallback
) {
// Always connect the listener even if notification-handling is disabled. Being a listener
// grants special permissions and it's not clear if other things will break if we lose those
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
index 014406f..69484b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
@@ -17,19 +17,19 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
import android.os.PowerManager
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
/** Interactor for the [NotificationShelf] */
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
class NotificationShelfInteractor
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 12956ab..2520738 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -19,6 +19,7 @@
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -32,7 +33,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch
@@ -43,7 +43,7 @@
* [NotificationShelfController] interface. Once the [LegacyNotificationShelfControllerImpl] is
* removed, this class can go away and the ViewBinder can be used directly.
*/
-@CentralSurfacesScope
+@SysUISingleton
class NotificationShelfViewBinderWrapperControllerImpl @Inject constructor() :
NotificationShelfController {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 36025e8..0b5e436 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -3992,7 +3992,7 @@
mNotificationsController.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
- cancelActiveSwipe();
+ resetAllSwipeState();
}
}
@@ -4058,7 +4058,7 @@
mGroupExpansionManager.collapseGroups();
mExpandHelper.cancelImmediately();
if (!mIsExpansionChanging) {
- cancelActiveSwipe();
+ resetAllSwipeState();
}
finalizeClearAllAnimation();
}
@@ -4387,7 +4387,7 @@
boolean nowHiddenAtAll = mAmbientState.isHiddenAtAll();
if (nowFullyHidden != wasFullyHidden) {
updateVisibility();
- mSwipeHelper.resetTouchState();
+ resetAllSwipeState();
}
if (!wasHiddenAtAll && nowHiddenAtAll) {
resetExposedMenuView(true /* animate */, true /* animate */);
@@ -5847,9 +5847,14 @@
}
}
- private void cancelActiveSwipe() {
+ private void resetAllSwipeState() {
+ Trace.beginSection("NSSL.resetAllSwipeState()");
mSwipeHelper.resetTouchState();
+ for (int i = 0; i < getChildCount(); i++) {
+ mSwipeHelper.forceResetSwipeState(getChildAt(i));
+ }
updateContinuousShadowDrawing();
+ Trace.endSection();
}
void updateContinuousShadowDrawing() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index a70862ae..aef623a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -56,11 +56,13 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
@@ -175,6 +177,7 @@
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardInteractor mKeyguardInteractor;
+ private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
private final NotificationLockscreenUserManager mLockscreenUserManager;
// TODO: CentralSurfaces should be encapsulated behind a Controller
private final CentralSurfaces mCentralSurfaces;
@@ -195,6 +198,7 @@
@Nullable
private Boolean mHistoryEnabled;
private int mBarState;
+ private boolean mIsBouncerShowingFromCentralSurfaces;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private final FeatureFlags mFeatureFlags;
private final NotificationTargetsHelper mNotificationTargetsHelper;
@@ -631,6 +635,7 @@
KeyguardMediaController keyguardMediaController,
KeyguardBypassController keyguardBypassController,
KeyguardInteractor keyguardInteractor,
+ PrimaryBouncerInteractor primaryBouncerInteractor,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
Optional<NotificationListViewModel> nsslViewModel,
@@ -680,6 +685,7 @@
mKeyguardMediaController = keyguardMediaController;
mKeyguardBypassController = keyguardBypassController;
mKeyguardInteractor = keyguardInteractor;
+ mPrimaryBouncerInteractor = primaryBouncerInteractor;
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
mViewModel = nsslViewModel;
@@ -1206,6 +1212,14 @@
}
/**
+ * Sets whether the bouncer is currently showing. Should only be called from
+ * {@link CentralSurfaces}.
+ */
+ public void setBouncerShowingFromCentralSurfaces(boolean bouncerShowing) {
+ mIsBouncerShowingFromCentralSurfaces = bouncerShowing;
+ }
+
+ /**
* Set the visibility of the view, and propagate it to specific children.
*
* @param visible either the view is visible or not.
@@ -1236,7 +1250,8 @@
// That avoids "No Notifications" to blink when transitioning to AOD.
// For more details, see: b/228790482
&& !isInTransitionToKeyguard()
- && !mCentralSurfaces.isBouncerShowing();
+ // Don't show any notification content if the bouncer is showing. See b/267060171.
+ && !isBouncerShowing();
mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
@@ -1244,6 +1259,24 @@
}
/**
+ * Returns whether the bouncer is currently showing.
+ *
+ * There's a possible timing difference between when CentralSurfaces marks the bouncer as not
+ * showing and when PrimaryBouncerInteractor marks the bouncer as not showing. (CentralSurfaces
+ * appears to mark the bouncer as showing for 10-200ms longer than PrimaryBouncerInteractor.)
+ *
+ * This timing difference could be load bearing, which is why we have a feature flag protecting
+ * where we fetch the value from. This flag is intended to be short-lived.
+ */
+ private boolean isBouncerShowing() {
+ if (mFeatureFlags.isEnabled(Flags.USE_REPOS_FOR_BOUNCER_SHOWING)) {
+ return mPrimaryBouncerInteractor.isBouncerShowing();
+ } else {
+ return mIsBouncerShowingFromCentralSurfaces;
+ }
+ }
+
+ /**
* Update the importantForAccessibility of NotificationStackScrollLayout.
* <p>
* We want the NSSL to be unimportant for accessibility when there's no
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 6f1c378..fc213b6 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
@@ -29,8 +29,6 @@
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.R;
import com.android.systemui.animation.ShadeInterpolation;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
@@ -189,9 +187,7 @@
private float interpolateFooterAlpha(AmbientState ambientState) {
float expansion = ambientState.getExpansionFraction();
- FeatureFlags flags = ambientState.getFeatureFlags();
- if (ambientState.isSmallScreen()
- || !flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+ if (ambientState.isSmallScreen()) {
return ShadeInterpolation.getContentAlpha(expansion);
}
LargeScreenShadeInterpolator interpolator = ambientState.getLargeScreenShadeInterpolator();
@@ -200,9 +196,7 @@
private float interpolateNotificationContentAlpha(AmbientState ambientState) {
float expansion = ambientState.getExpansionFraction();
- FeatureFlags flags = ambientState.getFeatureFlags();
- if (ambientState.isSmallScreen()
- || !flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+ if (ambientState.isSmallScreen()) {
return ShadeInterpolation.getContentAlpha(expansion);
}
LargeScreenShadeInterpolator interpolator = ambientState.getLargeScreenShadeInterpolator();
@@ -315,7 +309,8 @@
float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
if (mClipNotificationScrollToTop
- && ((isHeadsUp && !firstHeadsUp) || child.isHeadsUpAnimatingAway())
+ && !firstHeadsUp
+ && (isHeadsUp || child.isHeadsUpAnimatingAway())
&& newNotificationEnd > firstHeadsUpEnd
&& !ambientState.isShadeExpanded()) {
// The bottom of this view is peeking out from under the previous view.
@@ -619,13 +614,12 @@
updateViewWithShelf(view, viewState, shelfStart);
}
}
- // Avoid pulsing notification flicker during AOD to LS
- // A pulsing notification is already expanded, no need to expand it again with animation
- if (ambientState.isPulsingRow(view)) {
- expansionFraction = 1.0f;
+ viewState.height = getMaxAllowedChildHeight(view);
+ if (!view.isPinned() && !view.isHeadsUpAnimatingAway()
+ && !ambientState.isPulsingRow(view)) {
+ // The expansion fraction should not affect HUNs or pulsing notifications.
+ viewState.height *= expansionFraction;
}
- // Clip height of view right before shelf.
- viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction);
}
algorithmState.mCurrentYPosition +=
@@ -785,6 +779,8 @@
}
}
if (row.isPinned()) {
+ // Make sure row yTranslation is at maximum the HUN yTranslation,
+ // which accounts for AmbientState.stackTopMargin in split-shade.
childState.setYTranslation(
Math.max(childState.getYTranslation(), headsUpTranslation));
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
@@ -809,7 +805,11 @@
}
}
if (row.isHeadsUpAnimatingAway()) {
- childState.setYTranslation(Math.max(childState.getYTranslation(), mHeadsUpInset));
+ // Make sure row yTranslation is at maximum the HUN yTranslation,
+ // which accounts for AmbientState.stackTopMargin in split-shade.
+ childState.setYTranslation(
+ Math.max(childState.getYTranslation(), headsUpTranslation));
+ // keep it visible for the animation
childState.hidden = false;
}
}
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 217d32c..730ef57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -744,7 +744,7 @@
} 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.
- centralSurfaces?.collapseShade()
+ shadeControllerLazy.get().cancelExpansionAndCollapseShade()
}
// We should exit the dream to prevent the activity from starting below the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 0929a4c..18d8050 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -43,6 +43,7 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -197,7 +198,10 @@
/**
* Wakes up the device if the device was dozing.
+ *
+ * @deprecated Use {@link PowerInteractor#wakeUpIfDozing(String, int)} instead.
*/
+ @Deprecated
void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason);
/** */
@@ -224,8 +228,6 @@
NotificationPresenter getPresenter();
- boolean isPanelExpanded();
-
/**
* Used to dispatch initial touch events before crossing the threshold to pull down the
* notification shade. After that, since the launcher window is set to slippery, input
@@ -320,8 +322,6 @@
void setBouncerShowingOverDream(boolean bouncerShowingOverDream);
- void collapseShade();
-
int getWakefulnessState();
boolean isScreenFullyOff();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 337acb6..5e0cfd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -545,7 +545,7 @@
@Override
public void togglePanel() {
- if (mCentralSurfaces.isPanelExpanded()) {
+ if (mShadeViewController.isPanelExpanded()) {
mShadeController.animateCollapseShade();
} else {
mShadeController.animateExpandShade();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index a020da5..50e286f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -136,6 +136,7 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.camera.CameraIntents;
import com.android.systemui.charging.WiredChargingRippleController;
@@ -157,7 +158,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -627,7 +627,6 @@
private final UserSwitcherController mUserSwitcherController;
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
protected final BatteryController mBatteryController;
- protected boolean mPanelExpanded;
private UiModeManager mUiModeManager;
private LogMaker mStatusBarStateLog;
protected final NotificationIconAreaController mNotificationIconAreaController;
@@ -649,7 +648,9 @@
private final Optional<StartingSurface> mStartingSurfaceOptional;
private final ActivityIntentHelper mActivityIntentHelper;
- private NotificationStackScrollLayoutController mStackScrollerController;
+
+ @VisibleForTesting
+ protected NotificationStackScrollLayoutController mStackScrollerController;
private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
(extractor, which) -> updateTheme();
@@ -745,6 +746,7 @@
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
+ NotificationShelfController notificationShelfController,
DozeParameters dozeParameters,
ScrimController scrimController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
@@ -841,6 +843,7 @@
mAssistManagerLazy = assistManagerLazy;
mConfigurationController = configurationController;
mNotificationShadeWindowController = notificationShadeWindowController;
+ mNotificationShelfController = notificationShelfController;
mDozeServiceHost = dozeServiceHost;
mPowerManager = powerManager;
mDozeParameters = dozeParameters;
@@ -1522,22 +1525,15 @@
@VisibleForTesting
void onShadeExpansionFullyChanged(Boolean isExpanded) {
- if (mPanelExpanded != isExpanded) {
- mPanelExpanded = isExpanded;
- if (getShadeViewController() != null) {
- // Needed to update SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
- getShadeViewController().updateSystemUiStateFlags();
+ if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
+ if (DEBUG) {
+ Log.v(TAG, "clearing notification effects from Height");
}
- if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
- if (DEBUG) {
- Log.v(TAG, "clearing notification effects from Height");
- }
- clearNotificationEffects();
- }
+ clearNotificationEffects();
+ }
- if (!isExpanded) {
- mRemoteInputManager.onPanelCollapsed();
- }
+ if (!isExpanded) {
+ mRemoteInputManager.onPanelCollapsed();
}
}
@@ -1579,8 +1575,7 @@
mPresenter,
mNotifListContainer,
mStackScrollerController.getNotifStackController(),
- mNotificationActivityStarter,
- mCentralSurfacesComponent.getBindRowCallback());
+ mNotificationActivityStarter);
}
/**
@@ -1595,10 +1590,13 @@
/**
* Ask the display to wake up if currently dozing, else do nothing
*
+ * @deprecated Use {@link PowerInteractor#wakeUpIfDozing(String, int)} instead.
+ *
* @param time when to wake up
* @param why the reason for the wake up
*/
@Override
+ @Deprecated
public void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason) {
if (mDozing && mScreenOffAnimationController.allowWakeUpIfDozing()) {
mPowerManager.wakeUp(
@@ -1656,7 +1654,6 @@
mNotifListContainer = mCentralSurfacesComponent.getNotificationListContainer();
mPresenter = mCentralSurfacesComponent.getNotificationPresenter();
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
- mNotificationShelfController = mCentralSurfacesComponent.getNotificationShelfController();
mHeadsUpManager.addListener(mCentralSurfacesComponent.getStatusBarHeadsUpChangeListener());
@@ -1858,11 +1855,6 @@
}
}
- @Override
- public boolean isPanelExpanded() {
- return mPanelExpanded;
- }
-
/**
* Called when another window is about to transfer it's input focus.
*/
@@ -2932,6 +2924,7 @@
mBouncerShowing = bouncerShowing;
mKeyguardBypassController.setBouncerShowing(bouncerShowing);
mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
+ mStackScrollerController.setBouncerShowingFromCentralSurfaces(bouncerShowing);
setBouncerShowingForStatusBarComponents(bouncerShowing);
mStatusBarHideIconsForBouncerManager.setBouncerShowingAndTriggerUpdate(bouncerShowing);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
@@ -2973,19 +2966,6 @@
mShadeSurface.setBouncerShowing(bouncerShowing);
}
- /**
- * Collapses the notification shade if it is tracking or expanded.
- */
- @Override
- public void collapseShade() {
- if (mShadeSurface.isTracking()) {
- mNotificationShadeWindowViewController.cancelCurrentTouch();
- }
- if (mPanelExpanded && mState == StatusBarState.SHADE) {
- mShadeController.animateCollapseShade();
- }
- }
-
@VisibleForTesting
final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
@Override
@@ -3334,7 +3314,7 @@
mScrimController.setExpansionAffectsAlpha(!unlocking);
if (mAlternateBouncerInteractor.isVisibleState()) {
- if ((!isOccluded() || isPanelExpanded())
+ if ((!isOccluded() || mShadeSurface.isPanelExpanded())
&& (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
|| mTransitionToFullShadeProgress > 0f)) {
mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
@@ -3431,7 +3411,7 @@
protected Display mDisplay;
private int mDisplayId;
- protected NotificationShelfController mNotificationShelfController;
+ private final NotificationShelfController mNotificationShelfController;
private final Lazy<AssistManager> mAssistManagerLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 561bd91..fc3c85a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -229,12 +229,18 @@
}
}
- public float getLockscreenMinStackScrollerPadding() {
+ /**
+ * @param nsslTop NotificationStackScrollLayout top, which is below top of the srceen.
+ * @return Distance from nsslTop to top of the first view in the lockscreen shade.
+ */
+ public float getLockscreenNotifPadding(float nsslTop) {
if (mBypassEnabled) {
- return mUnlockedStackScrollerPadding;
+ return mUnlockedStackScrollerPadding - nsslTop;
} else if (mIsSplitShade) {
- return mSplitShadeTargetTopMargin + mUserSwitchHeight;
+ return mSplitShadeTargetTopMargin + mUserSwitchHeight - nsslTop;
} else {
+ // Non-bypass portrait shade already uses values from nsslTop
+ // so we don't need to subtract it here.
return mMinTopMargin + mKeyguardStatusHeight;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 25ecf1a..47c4023 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -59,7 +59,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -881,24 +881,11 @@
mBehindAlpha = 1;
mNotificationsAlpha = behindFraction * mDefaultScrimAlpha;
} else {
- if (mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
- mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha(
- mPanelExpansionFraction * mDefaultScrimAlpha);
- mNotificationsAlpha =
- mLargeScreenShadeInterpolator.getNotificationScrimAlpha(
- mPanelExpansionFraction);
- } else {
- // Behind scrim will finish fading in at 30% expansion.
- float behindFraction = MathUtils
- .constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
- mBehindAlpha = behindFraction * mDefaultScrimAlpha;
- // Delay fade-in of notification scrim a bit further, to coincide with the
- // behind scrim finishing fading in.
- // Also to coincide with the view starting to fade in, otherwise the empty
- // panel can be quite jarring.
- mNotificationsAlpha = MathUtils
- .constrainedMap(0f, 1f, 0.3f, 0.75f, mPanelExpansionFraction);
- }
+ mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha(
+ mPanelExpansionFraction * mDefaultScrimAlpha);
+ mNotificationsAlpha =
+ mLargeScreenShadeInterpolator.getNotificationScrimAlpha(
+ mPanelExpansionFraction);
}
mBehindTint = mState.getBehindTint();
mInFrontAlpha = 0;
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 f11b8e2..bb4aacb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -18,7 +18,7 @@
import static android.view.WindowInsets.Type.navigationBars;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@@ -58,11 +58,11 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.data.BouncerView;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.ui.BouncerView;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 5624e28..3b56d27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -52,7 +52,6 @@
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
@@ -68,9 +67,7 @@
import javax.inject.Inject;
@CentralSurfacesComponent.CentralSurfacesScope
-class StatusBarNotificationPresenter implements NotificationPresenter,
- NotificationRowBinderImpl.BindRowCallback,
- CommandQueue.Callbacks {
+class StatusBarNotificationPresenter implements NotificationPresenter, CommandQueue.Callbacks {
private static final String TAG = "StatusBarNotificationPresenter";
private final ActivityStarter mActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java
index 26c483c..d94e434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterModule.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import com.android.systemui.statusbar.NotificationPresenter;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import dagger.Binds;
import dagger.Module;
@@ -26,8 +25,4 @@
public abstract class StatusBarNotificationPresenterModule {
@Binds
abstract NotificationPresenter bindPresenter(StatusBarNotificationPresenter impl);
-
- @Binds
- abstract NotificationRowBinderImpl.BindRowCallback bindBindRowCallback(
- StatusBarNotificationPresenter impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index 158f961..64c798b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -27,9 +27,7 @@
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.statusbar.NotificationPresenter;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule;
@@ -90,9 +88,6 @@
NotificationShadeWindowView getNotificationShadeWindowView();
/** */
- NotificationShelfController getNotificationShelfController();
-
- /** */
NotificationStackScrollLayoutController getNotificationStackScrollLayoutController();
/**
@@ -134,7 +129,5 @@
NotificationPresenter getNotificationPresenter();
- NotificationRowBinderImpl.BindRowCallback getBindRowCallback();
-
NotificationListContainer getNotificationListContainer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 4ccbc5a..260d986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -23,24 +23,15 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelView;
import com.android.systemui.shade.NotificationPanelViewController;
-import com.android.systemui.shade.NotificationShadeWindowView;
-import com.android.systemui.shade.NotificationsQuickSettingsContainer;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl;
-import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
-import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -68,7 +59,6 @@
import java.util.concurrent.Executor;
import javax.inject.Named;
-import javax.inject.Provider;
@Module(subcomponents = StatusBarFragmentComponent.class,
includes = {
@@ -80,56 +70,11 @@
public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
/** */
- @Provides
- @CentralSurfacesComponent.CentralSurfacesScope
- public static NotificationShelf providesNotificationShelf(LayoutInflater layoutInflater,
- NotificationStackScrollLayout notificationStackScrollLayout) {
- NotificationShelf view = (NotificationShelf) layoutInflater.inflate(
- R.layout.status_bar_notification_shelf, notificationStackScrollLayout, false);
-
- if (view == null) {
- throw new IllegalStateException(
- "R.layout.status_bar_notification_shelf could not be properly inflated");
- }
- return view;
- }
-
- /** */
- @Provides
- @CentralSurfacesComponent.CentralSurfacesScope
- public static NotificationShelfController providesStatusBarWindowView(
- FeatureFlags featureFlags,
- Provider<NotificationShelfViewBinderWrapperControllerImpl> newImpl,
- NotificationShelfComponent.Builder notificationShelfComponentBuilder,
- NotificationShelf notificationShelf) {
- if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- return newImpl.get();
- } else {
- NotificationShelfComponent component = notificationShelfComponentBuilder
- .notificationShelf(notificationShelf)
- .build();
- LegacyNotificationShelfControllerImpl notificationShelfController =
- component.getNotificationShelfController();
- notificationShelfController.init();
-
- return notificationShelfController;
- }
- }
-
- /** */
@Binds
@CentralSurfacesComponent.CentralSurfacesScope
abstract ShadeViewController bindsShadeViewController(
NotificationPanelViewController notificationPanelViewController);
- /** */
- @Provides
- @CentralSurfacesComponent.CentralSurfacesScope
- public static NotificationsQuickSettingsContainer getNotificationsQuickSettingsContainer(
- NotificationShadeWindowView notificationShadeWindowView) {
- return notificationShadeWindowView.findViewById(R.id.notification_container_parent);
- }
-
@Binds
@IntoSet
abstract StatusBarBoundsProvider.BoundsChangeListener sysBarAttrsListenerAsBoundsListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 23afd8b3..d472c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -393,6 +393,31 @@
}
}
+ /**
+ * Notes that the user took an action on an entry that might indirectly cause the system or the
+ * app to remove the notification.
+ *
+ * @param entry the entry that might be indirectly removed by the user's action
+ *
+ * @see com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator#mActionPressListener
+ * @see #canRemoveImmediately(String)
+ */
+ public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) {
+ HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
+ if (headsUpEntry != null) {
+ headsUpEntry.userActionMayIndirectlyRemove = true;
+ }
+ }
+
+ @Override
+ public boolean canRemoveImmediately(@NonNull String key) {
+ HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
+ if (headsUpEntry != null && headsUpEntry.userActionMayIndirectlyRemove) {
+ return true;
+ }
+ return super.canRemoveImmediately(key);
+ }
+
@NonNull
@Override
protected HeadsUpEntry createAlertEntry() {
@@ -421,6 +446,8 @@
*/
protected class HeadsUpEntry extends AlertEntry {
public boolean remoteInputActive;
+ public boolean userActionMayIndirectlyRemove;
+
protected boolean expanded;
protected boolean wasUnpinned;
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/PackageManagerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/PackageManagerExt.kt
new file mode 100644
index 0000000..891ee0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/PackageManagerExt.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.util.kotlin
+
+import android.annotation.WorkerThread
+import android.content.pm.ComponentInfo
+import android.content.pm.PackageManager
+import com.android.systemui.util.Assert
+
+@WorkerThread
+fun PackageManager.isComponentActuallyEnabled(componentInfo: ComponentInfo): Boolean {
+ Assert.isNotMainThread()
+ return when (getComponentEnabledSetting(componentInfo.componentName)) {
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> false
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> componentInfo.isEnabled
+ else -> false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b848d2e..f37a9b5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -390,8 +390,6 @@
public void init(int windowType, Callback callback) {
initDialog(mActivityManager.getLockTaskModeState());
- mAccessibility.init();
-
mController.addCallback(mControllerCallbackH, mHandler);
mController.getState();
@@ -478,8 +476,7 @@
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
- mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
@@ -677,6 +674,7 @@
initRingerH();
initSettingsH(lockTaskModeState);
initODICaptionsH();
+ mAccessibility.init();
}
private boolean isWindowGravityLeft() {
@@ -930,6 +928,7 @@
showRingerDrawer();
}
});
+ updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
mRingerDrawerVibrate.setOnClickListener(
new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE));
@@ -992,6 +991,19 @@
: 0;
}
+ @VisibleForTesting String getSelectedRingerContainerDescription() {
+ return mSelectedRingerContainer == null ? null :
+ mSelectedRingerContainer.getContentDescription().toString();
+ }
+
+ @VisibleForTesting void toggleRingerDrawer(boolean show) {
+ if (show) {
+ showRingerDrawer();
+ } else {
+ hideRingerDrawer();
+ }
+ }
+
/** Animates in the ringer drawer. */
private void showRingerDrawer() {
if (mIsRingerDrawerOpen) {
@@ -1069,12 +1081,7 @@
.start();
}
- // When the ringer drawer is open, tapping the currently selected ringer will set the ringer
- // to the current ringer mode. Change the content description to that, instead of the 'tap
- // to change ringer mode' default.
- mSelectedRingerContainer.setContentDescription(
- mContext.getString(getStringDescriptionResourceForRingerMode(
- mState.ringerModeInternal)));
+ updateSelectedRingerContainerDescription(true);
mIsRingerDrawerOpen = true;
}
@@ -1120,14 +1127,38 @@
.translationY(0f)
.start();
- // When the drawer is closed, tapping the selected ringer drawer will open it, allowing the
- // user to change the ringer.
- mSelectedRingerContainer.setContentDescription(
- mContext.getString(R.string.volume_ringer_change));
+ updateSelectedRingerContainerDescription(false);
mIsRingerDrawerOpen = false;
}
+
+ /**
+ * @param open false to set the description when drawer is closed
+ */
+ private void updateSelectedRingerContainerDescription(boolean open) {
+ if (mState == null || mSelectedRingerContainer == null) return;
+
+ String currentMode = mContext.getString(getStringDescriptionResourceForRingerMode(
+ mState.ringerModeInternal));
+ String tapToSelect;
+
+ if (open) {
+ // When the ringer drawer is open, tapping the currently selected ringer will set the
+ // ringer to the current ringer mode. Change the content description to that, instead of
+ // the 'tap to change ringer mode' default.
+ tapToSelect = "";
+
+ } else {
+ // When the drawer is closed, tapping the selected ringer drawer will open it, allowing
+ // the user to change the ringer. The user needs to know that, and also the current mode
+ currentMode += ", ";
+ tapToSelect = mContext.getString(R.string.volume_ringer_change);
+ }
+
+ mSelectedRingerContainer.setContentDescription(currentMode + tapToSelect);
+ }
+
private void initSettingsH(int lockTaskModeState) {
if (mSettingsView != null) {
mSettingsView.setVisibility(
@@ -1703,7 +1734,7 @@
});
}
- private int getStringDescriptionResourceForRingerMode(int mode) {
+ @VisibleForTesting int getStringDescriptionResourceForRingerMode(int mode) {
switch (mode) {
case RINGER_MODE_SILENT:
return R.string.volume_ringer_status_silent;
@@ -1785,6 +1816,7 @@
updateVolumeRowH(row);
}
updateRingerH();
+ updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
mWindow.setTitle(composeWindowTitle());
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index f5cd0ca..319a02d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -50,6 +50,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -59,6 +60,7 @@
@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@SmallTest
+@Ignore("b/286245842")
public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private static final int TARGET_USER_ID = KeyguardUpdateMonitor.getCurrentUser();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 8c71392..0dcd404 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -23,7 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -47,6 +47,7 @@
import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.yield
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -121,7 +122,7 @@
bouncerRepository = bouncerRepository,
configurationRepository = FakeConfigurationRepository(),
),
- KeyguardTransitionInteractor(repository = transitionRepository),
+ KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
broadcastDispatcher,
batteryController,
keyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 8dc1e8f..65c677e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -73,6 +73,7 @@
private FrameLayout mSmallClockFrame;
private FrameLayout mLargeClockFrame;
+ private KeyguardStatusAreaView mStatusArea;
KeyguardClockSwitch mKeyguardClockSwitch;
@@ -110,6 +111,7 @@
(KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large);
+ mStatusArea = mKeyguardClockSwitch.findViewById(R.id.keyguard_status_area);
mKeyguardClockSwitch.mChildrenAreLaidOut = true;
}
@@ -186,6 +188,7 @@
mKeyguardClockSwitch.mClockInAnim.end();
mKeyguardClockSwitch.mClockOutAnim.end();
+ mKeyguardClockSwitch.mStatusAreaAnim.end();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
@@ -209,6 +212,7 @@
mKeyguardClockSwitch.mClockInAnim.end();
mKeyguardClockSwitch.mClockOutAnim.end();
+ mKeyguardClockSwitch.mStatusAreaAnim.end();
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
@@ -231,6 +235,31 @@
}
@Test
+ public void switchingToSmallClockAnimation_resetsStatusArea() {
+ mKeyguardClockSwitch.switchToClock(SMALL, true);
+
+ mKeyguardClockSwitch.mClockInAnim.end();
+ mKeyguardClockSwitch.mClockOutAnim.end();
+ mKeyguardClockSwitch.mStatusAreaAnim.end();
+
+ assertThat(mStatusArea.getTranslationX()).isEqualTo(0);
+ assertThat(mStatusArea.getTranslationY()).isEqualTo(0);
+ assertThat(mStatusArea.getScaleX()).isEqualTo(1);
+ assertThat(mStatusArea.getScaleY()).isEqualTo(1);
+ }
+
+ @Test
+ public void switchingToSmallClockNoAnimation_resetsStatusArea() {
+ mKeyguardClockSwitch.switchToClock(SMALL, false);
+
+ assertThat(mStatusArea.getTranslationX()).isEqualTo(0);
+ assertThat(mStatusArea.getTranslationY()).isEqualTo(0);
+ assertThat(mStatusArea.getScaleX()).isEqualTo(1);
+ assertThat(mStatusArea.getScaleY()).isEqualTo(1);
+ }
+
+
+ @Test
public void switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore() {
assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isTrue();
assertThat(mKeyguardClockSwitch.switchToClock(LARGE, /* animate */ true)).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index e1ba488..e561f1f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -18,7 +18,7 @@
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
import static com.google.common.truth.Truth.assertThat;
@@ -67,7 +67,7 @@
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -587,21 +587,6 @@
}
@Test
- public void testSecurityCallbackFinish() {
- when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
- when(mKeyguardUpdateMonitor.isUserUnlocked(0)).thenReturn(true);
- mKeyguardSecurityContainerController.finish(true, 0);
- verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt());
- }
-
- @Test
- public void testSecurityCallbackFinish_cannotDismissLockScreenAndNotStrongAuth() {
- when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
- mKeyguardSecurityContainerController.finish(false, 0);
- verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
- }
-
- @Test
public void testOnStartingToHide() {
mKeyguardSecurityContainerController.onStartingToHide();
verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt
new file mode 100644
index 0000000..e6b6964
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt
@@ -0,0 +1,44 @@
+package com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class KeyguardStatusAreaViewTest : SysuiTestCase() {
+
+ private lateinit var view: KeyguardStatusAreaView
+
+ @Before
+ fun setUp() {
+ view = KeyguardStatusAreaView(context)
+ }
+
+ @Test
+ fun checkTranslationX_AddedTotals() {
+ view.translateXFromClockDesign = 10f
+ assertEquals(10f, view.translationX)
+
+ view.translateXFromAod = 20f
+ assertEquals(30f, view.translationX)
+
+ view.translateXFromUnfold = 30f
+ assertEquals(60f, view.translationX)
+ }
+
+ @Test
+ fun checkTranslationY_AddedTotals() {
+ view.translateYFromClockSize = 10f
+ assertEquals(10f, view.translationY)
+
+ view.translateYFromClockDesign = 20f
+ assertEquals(30f, view.translationY)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 419d045..0edfd77 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -38,6 +38,7 @@
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
+import static com.android.systemui.flags.Flags.FP_LISTEN_OCCLUDING_APPS;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -134,6 +135,7 @@
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
@@ -277,6 +279,7 @@
private final Executor mBackgroundExecutor = Runnable::run;
private final Executor mMainExecutor = Runnable::run;
private TestableLooper mTestableLooper;
+ private FakeFeatureFlags mFeatureFlags;
private Handler mHandler;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
private MockitoSession mMockitoSession;
@@ -325,6 +328,8 @@
mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
+ mFeatureFlags = new FakeFeatureFlags();
+ mFeatureFlags.set(FP_LISTEN_OCCLUDING_APPS, false);
when(mSecureSettings.getUriFor(anyString())).thenReturn(mURI);
@@ -1430,6 +1435,23 @@
}
@Test
+ public void testOccludingAppFingerprintListeningState_featureFlagEnabled() {
+ mFeatureFlags.set(FP_LISTEN_OCCLUDING_APPS, true);
+
+ // GIVEN keyguard isn't visible (app occluding)
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+ // THEN we SHOULD listen for non-UDFPS fingerprint
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isEqualTo(true);
+
+ // THEN we should listen for udfps (hiding of mechanism to actually auth is
+ // controlled by UdfpsKeyguardViewController)
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(true);
+ }
+
+ @Test
public void testOccludingAppFingerprintListeningState() {
// GIVEN keyguard isn't visible (app occluding)
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
@@ -2800,6 +2822,16 @@
);
}
+ @Test
+ public void testOnSimStateChanged_Unknown() {
+ KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback = spy(
+ KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);
+ mKeyguardUpdateMonitor.handleSimStateChange(-1, 0, TelephonyManager.SIM_STATE_UNKNOWN);
+ verify(keyguardUpdateMonitorCallback).onSimStateChanged(-1, 0,
+ TelephonyManager.SIM_STATE_UNKNOWN);
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
@@ -3126,7 +3158,7 @@
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig, mDevicePostureController,
- Optional.of(mInteractiveToAuthProvider));
+ Optional.of(mInteractiveToAuthProvider), mFeatureFlags);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index bdf6bee..c88c4d6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -158,7 +158,8 @@
mVibrator,
mAuthRippleController,
mResources,
- new KeyguardTransitionInteractor(mTransitionRepository),
+ new KeyguardTransitionInteractor(mTransitionRepository,
+ TestScopeProvider.getTestScope().getBackgroundScope()),
KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
mFeatureFlags
);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
similarity index 71%
copy from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt
copy to packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
index 05cdeaa..6c35734 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BouncerShowMessageModel.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-
-package com.android.systemui.keyguard.shared.model
-
-import android.content.res.ColorStateList
-
-/** Show a keyguard message to the bouncer. */
-data class BouncerShowMessageModel(val message: String?, val colorStateList: ColorStateList?)
+package com.android.keyguard
+import kotlinx.coroutines.test.TestScope
+class TestScopeProvider {
+ companion object {
+ @JvmStatic fun getTestScope() = TestScope()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index a0fdc8f..24a5e80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -48,8 +48,7 @@
@Test
public void testInitDependency() throws ExecutionException, InterruptedException {
Dependency.clearDependencies();
- SystemUIInitializer initializer =
- SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ SystemUIInitializer initializer = new SystemUIInitializerImpl(mContext);
initializer.init(true);
Dependency dependency = initializer.getSysUIComponent().createDependency();
dependency.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index b3f9958..275723b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -20,7 +20,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +28,7 @@
import static junit.framework.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -525,13 +525,13 @@
private void setupMagnificationCapabilityAndMode(int capability, int mode) {
when(mSecureSettings.getIntForUser(
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
- ACCESSIBILITY_MAGNIFICATION_MODE_NONE,
- UserHandle.USER_CURRENT)).thenReturn(capability);
+ eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY),
+ anyInt(),
+ eq(UserHandle.USER_CURRENT))).thenReturn(capability);
when(mSecureSettings.getIntForUser(
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
- ACCESSIBILITY_MAGNIFICATION_MODE_NONE,
- UserHandle.USER_CURRENT)).thenReturn(mode);
+ eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE),
+ anyInt(),
+ eq(UserHandle.USER_CURRENT))).thenReturn(mode);
}
private void setupScaleInSecureSettings(float scale) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
index 57a355f..5e1a8e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
@@ -37,7 +37,7 @@
private fun assertSameAxes(expect: Font, actual: Font) {
val expectAxes = expect.axes?.also { it.sortBy { axis -> axis.tag } }
val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } }
- assertThat(expectAxes).isEqualTo(actualAxes)
+ assertThat(actualAxes).isEqualTo(expectAxes)
}
private fun assertSameAxes(expectVarSettings: String, actual: Font) {
@@ -46,7 +46,7 @@
it.sortBy { axis -> axis.tag }
}
val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } }
- assertThat(expectAxes).isEqualTo(actualAxes)
+ assertThat(actualAxes).isEqualTo(expectAxes)
}
@Test
@@ -61,7 +61,7 @@
val interp = FontInterpolator()
assertSameAxes(startFont, interp.lerp(startFont, endFont, 0f))
assertSameAxes(endFont, interp.lerp(startFont, endFont, 1f))
- assertSameAxes("'wght' 496, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
+ assertSameAxes("'wght' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
}
@Test
@@ -74,7 +74,7 @@
.build()
val interp = FontInterpolator()
- assertSameAxes("'wght' 249, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
+ assertSameAxes("'wght' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
}
@Test
@@ -118,7 +118,7 @@
.setFontVariationSettings("'wght' 1")
.build()
val resultFont = interp.lerp(startFont, endFont, 0.5f)
- for (i in 0..FONT_CACHE_MAX_ENTRIES + 1) {
+ for (i in 0..interp.cacheMaxEntries + 1) {
val f1 = Font.Builder(sFont)
.setFontVariationSettings("'wght' ${i * 100}")
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
index 0798d73..d1ac0e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
@@ -21,6 +21,7 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.view.LaunchableFrameLayout
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS
index adb10f0..5420c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS
@@ -1,4 +1,5 @@
set noparent
+# Bug component: 879035
include /services/core/java/com/android/server/biometrics/OWNERS
beverlyt@google.com
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index 2908e75..d022653 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -58,11 +58,11 @@
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 9dcdc46..2248755 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -46,8 +46,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -114,6 +114,8 @@
@Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
@Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock private lateinit var udfpsUtils: UdfpsUtils
+ @Mock private lateinit var udfpsKeyguardAccessibilityDelegate:
+ UdfpsKeyguardAccessibilityDelegate
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
@@ -144,7 +146,8 @@
configurationController, keyguardStateController, unlockedScreenOffAnimationController,
udfpsDisplayMode, secureSettings, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
- primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable, udfpsUtils
+ primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable, udfpsUtils,
+ udfpsKeyguardAccessibilityDelegate,
)
block()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index b2ccd60..72cd822 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -87,9 +87,9 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -217,6 +217,8 @@
private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
// Capture listeners so that they can be used to send events
@Captor
@@ -315,7 +317,8 @@
mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker,
mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils,
- mock(KeyguardFaceAuthInteractor.class));
+ mock(KeyguardFaceAuthInteractor.class),
+ mUdfpsKeyguardAccessibilityDelegate);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt
new file mode 100644
index 0000000..921ff09
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.biometrics
+
+import android.testing.TestableLooper
+import android.view.View
+import android.view.accessibility.AccessibilityNodeInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.argumentCaptor
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+@TestableLooper.RunWithLooper
+class UdfpsKeyguardAccessibilityDelegateTest : SysuiTestCase() {
+
+ @Mock private lateinit var keyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var hostView: View
+ private lateinit var underTest: UdfpsKeyguardAccessibilityDelegate
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ UdfpsKeyguardAccessibilityDelegate(
+ context.resources,
+ keyguardViewManager,
+ )
+ }
+
+ @Test
+ fun onInitializeAccessibilityNodeInfo_clickActionAdded() {
+ // WHEN node is initialized
+ val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
+ underTest.onInitializeAccessibilityNodeInfo(hostView, mockedNodeInfo)
+
+ // THEN a11y action is added
+ val argumentCaptor = argumentCaptor<AccessibilityNodeInfo.AccessibilityAction>()
+ verify(mockedNodeInfo).addAction(argumentCaptor.capture())
+
+ // AND the a11y action is a click action
+ assertEquals(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+ argumentCaptor.value.id
+ )
+ }
+
+ @Test
+ fun performAccessibilityAction_actionClick_showsPrimaryBouncer() {
+ // WHEN click action is performed
+ val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
+ underTest.performAccessibilityAction(
+ hostView,
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+ null
+ )
+
+ // THEN primary bouncer shows
+ verify(keyguardViewManager).showPrimaryBouncer(anyBoolean())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
index 0d3b394..032753a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
@@ -31,8 +31,8 @@
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionListener;
@@ -73,6 +73,7 @@
protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
protected @Mock AlternateBouncerInteractor mAlternateBouncerInteractor;
+ protected @Mock UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
protected FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@@ -167,7 +168,8 @@
mActivityLaunchAnimator,
mFeatureFlags,
mPrimaryBouncerInteractor,
- mAlternateBouncerInteractor);
+ mAlternateBouncerInteractor,
+ mUdfpsKeyguardAccessibilityDelegate);
return controller;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index ffad326..9df06dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -22,20 +22,20 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.RoboPilotTest
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
index 1f2b64d..263ce1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -56,6 +56,7 @@
foldProvider,
KeyguardTransitionInteractor(
keyguardTransitionRepository,
+ testScope.backgroundScope
),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
index 689bb00..fff1b81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
@@ -33,6 +33,7 @@
with(PromptAuthState(isAuthenticated = false)) {
assertThat(isNotAuthenticated).isTrue()
assertThat(isAuthenticatedAndConfirmed).isFalse()
+ assertThat(isAuthenticatedAndExplicitlyConfirmed).isFalse()
assertThat(isAuthenticatedByFace).isFalse()
assertThat(isAuthenticatedByFingerprint).isFalse()
}
@@ -43,6 +44,7 @@
with(PromptAuthState(isAuthenticated = true)) {
assertThat(isNotAuthenticated).isFalse()
assertThat(isAuthenticatedAndConfirmed).isTrue()
+ assertThat(isAuthenticatedAndExplicitlyConfirmed).isFalse()
assertThat(isAuthenticatedByFace).isFalse()
assertThat(isAuthenticatedByFingerprint).isFalse()
}
@@ -50,10 +52,12 @@
with(PromptAuthState(isAuthenticated = true, needsUserConfirmation = true)) {
assertThat(isNotAuthenticated).isFalse()
assertThat(isAuthenticatedAndConfirmed).isFalse()
+ assertThat(isAuthenticatedAndExplicitlyConfirmed).isFalse()
assertThat(isAuthenticatedByFace).isFalse()
assertThat(isAuthenticatedByFingerprint).isFalse()
- assertThat(asConfirmed().isAuthenticatedAndConfirmed).isTrue()
+ assertThat(asExplicitlyConfirmed().isAuthenticatedAndConfirmed).isTrue()
+ assertThat(asExplicitlyConfirmed().isAuthenticatedAndExplicitlyConfirmed).isTrue()
}
}
@@ -64,6 +68,7 @@
) {
assertThat(isNotAuthenticated).isFalse()
assertThat(isAuthenticatedAndConfirmed).isTrue()
+ assertThat(isAuthenticatedAndExplicitlyConfirmed).isFalse()
assertThat(isAuthenticatedByFace).isTrue()
assertThat(isAuthenticatedByFingerprint).isFalse()
}
@@ -79,6 +84,7 @@
) {
assertThat(isNotAuthenticated).isFalse()
assertThat(isAuthenticatedAndConfirmed).isTrue()
+ assertThat(isAuthenticatedAndExplicitlyConfirmed).isFalse()
assertThat(isAuthenticatedByFace).isFalse()
assertThat(isAuthenticatedByFingerprint).isTrue()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
index 9e79849..992ee1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/factory/BouncerMessageFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.data.factory
+package com.android.systemui.bouncer.data.factory
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -26,7 +26,7 @@
import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.StringSubject
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepositoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
index 1277fc0..de712da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/data/repository/BouncerMessageRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.data.repository
+package com.android.systemui.bouncer.data.repo
import android.content.pm.UserInfo
import android.hardware.biometrics.BiometricSourceType
@@ -45,10 +45,12 @@
import com.android.systemui.R.string.kg_prompt_unattended_update
import com.android.systemui.R.string.kg_trust_agent_disabled
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.keyguard.bouncer.shared.model.Message
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
similarity index 64%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
index b3104b7..a049191 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -1,20 +1,4 @@
-/*
- * 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.keyguard.data.repository
+package com.android.systemui.bouncer.data.repository
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -24,14 +8,14 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.SystemClock
-import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineScope
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
+import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@@ -59,6 +43,7 @@
@Test
fun changingFlowValueTriggersLogging() = runBlocking {
underTest.setPrimaryShow(true)
- verify(bouncerLogger).logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
+ Mockito.verify(bouncerLogger)
+ .logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index ca6b8d5..37b9ca4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index b0af310..8e5256e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.bouncer.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.content.pm.UserInfo
import android.testing.TestableLooper
@@ -26,14 +26,14 @@
import com.android.systemui.R.string.keyguard_enter_pin
import com.android.systemui.R.string.kg_too_many_failed_attempts_countdown
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.keyguard.bouncer.shared.model.Message
-import com.android.systemui.keyguard.data.repository.FakeBouncerMessageRepository
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
index 2b135cc..a81ca86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
similarity index 92%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index b5cb44a..f892453 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
@@ -27,17 +27,17 @@
import com.android.systemui.DejankUtils
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.bouncer.ui.BouncerViewDelegate
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
-import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
@@ -407,6 +407,7 @@
whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
.thenReturn(true)
+ whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(true)
// WHEN bouncer show is requested
underTest.show(true)
@@ -424,6 +425,25 @@
}
@Test
+ fun noDelayBouncer_biometricsAllowed_postureDoesNotAllowFaceAuth() {
+ mainHandler.setMode(FakeHandler.Mode.QUEUEING)
+
+ // GIVEN bouncer should not be delayed because device isn't in the right posture for
+ // face auth
+ whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+ whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
+ .thenReturn(true)
+ whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(false)
+
+ // WHEN bouncer show is requested
+ underTest.show(true)
+
+ // THEN primary show & primary showing soon are updated immediately
+ verify(repository).setPrimaryShow(true)
+ verify(repository).setPrimaryShowingSoon(false)
+ }
+
+ @Test
fun delayBouncerWhenActiveUnlockPossible() {
testScope.run {
mainHandler.setMode(FakeHandler.Mode.QUEUEING)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index b288fbc..665456d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.domain.interactor
+package com.android.systemui.bouncer.domain.interactor
import android.os.Looper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -23,13 +23,13 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
similarity index 92%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 15707c9..8236165 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.bouncer.ui.viewmodel
import android.os.Looper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -23,16 +23,16 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.utils.os.FakeHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index 26cbd77..724c9d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -116,11 +116,7 @@
@Test
fun testBindAndLoad_cancel() {
- val callback = object : ControlsBindingController.LoadCallback {
- override fun error(message: String) {}
-
- override fun accept(t: List<Control>) {}
- }
+ val callback = mock(ControlsBindingController.LoadCallback::class.java)
val subscription = mock(IControlsSubscription::class.java)
val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
@@ -130,6 +126,7 @@
canceller.run()
verify(providers[0]).cancelSubscription(subscription)
+ verify(callback).error(any())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
index 7fb088e..bd4e8da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -27,16 +28,20 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
class ControlsTileResourceConfigurationImplTest : SysuiTestCase() {
+
+ @Test
+ fun getPackageName() {
+ assertThat(ControlsTileResourceConfigurationImpl().getPackageName()).isNull()
+ }
+
@Test
fun getTileImageId() {
val instance = ControlsTileResourceConfigurationImpl()
- assertEquals(instance.getTileImageId(),
- R.drawable.controls_icon)
+ assertEquals(instance.getTileImageId(), R.drawable.controls_icon)
}
@Test
fun getTileTitleId() {
val instance = ControlsTileResourceConfigurationImpl()
- assertEquals(instance.getTileTitleId(),
- R.string.quick_controls_title)
+ assertEquals(instance.getTileTitleId(), R.string.quick_controls_title)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
index 9144b13..0b27bc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
@@ -22,10 +22,10 @@
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
import com.android.systemui.SysuiTestCase
-import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -40,32 +40,25 @@
import org.mockito.Answers
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ControlsComponentTest : SysuiTestCase() {
- @Mock
- private lateinit var controller: ControlsController
- @Mock
- private lateinit var uiController: ControlsUiController
- @Mock
- private lateinit var listingController: ControlsListingController
- @Mock
- private lateinit var keyguardStateController: KeyguardStateController
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var controller: ControlsController
+ @Mock private lateinit var uiController: ControlsUiController
+ @Mock private lateinit var listingController: ControlsListingController
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var userTracker: UserTracker
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
@Mock
private lateinit var optionalControlsTileResourceConfiguration:
- Optional<ControlsTileResourceConfiguration>
- @Mock
- private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
+ Optional<ControlsTileResourceConfiguration>
+ @Mock private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
@@ -123,8 +116,7 @@
@Test
fun testFeatureEnabledAndCannotShowOnLockScreenVisibility() {
- `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
- .thenReturn(STRONG_AUTH_NOT_REQUIRED)
+ `when`(lockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
controlsSettingsRepository.setCanShowControlsInLockscreen(false)
val component = setupComponent(true)
@@ -134,8 +126,7 @@
@Test
fun testFeatureEnabledAndCanShowOnLockScreenVisibility() {
- `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
- .thenReturn(STRONG_AUTH_NOT_REQUIRED)
+ `when`(lockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
controlsSettingsRepository.setCanShowControlsInLockscreen(true)
val component = setupComponent(true)
@@ -146,8 +137,7 @@
@Test
fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() {
controlsSettingsRepository.setCanShowControlsInLockscreen(false)
- `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
- .thenReturn(STRONG_AUTH_NOT_REQUIRED)
+ `when`(lockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(true)
val component = setupComponent(true)
@@ -158,8 +148,7 @@
fun testGetTileImageId() {
val tileImageId = 0
- `when`(controlsTileResourceConfiguration.getTileImageId())
- .thenReturn(tileImageId)
+ `when`(controlsTileResourceConfiguration.getTileImageId()).thenReturn(tileImageId)
val component = setupComponent(true)
assertEquals(component.getTileImageId(), tileImageId)
}
@@ -168,12 +157,19 @@
fun testGetTileTitleId() {
val tileTitleId = 0
- `when`(controlsTileResourceConfiguration.getTileTitleId())
- .thenReturn(tileTitleId)
+ `when`(controlsTileResourceConfiguration.getTileTitleId()).thenReturn(tileTitleId)
val component = setupComponent(true)
assertEquals(component.getTileTitleId(), tileTitleId)
}
+ @Test
+ fun getPackageName() {
+ val packageName = "packageName"
+ `when`(controlsTileResourceConfiguration.getPackageName()).thenReturn(packageName)
+ val component = setupComponent(true)
+ assertEquals(component.getPackageName(), packageName)
+ }
+
private fun setupComponent(enabled: Boolean): ControlsComponent {
return ControlsComponent(
enabled,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 039682c..a00e545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -23,9 +22,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.anyLong
import org.mockito.Mockito.atLeastOnce
-import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -92,16 +89,10 @@
}
@Test
- fun testWakeUpCallsExecutor() {
- val mockExecutor: DelayableExecutor = mock()
- val mockCallback: Runnable = mock()
+ fun testWakeUpSetsExitAnimationsRunning() {
+ controller.wakeUp()
- controller.wakeUp(
- doneCallback = mockCallback,
- executor = mockExecutor,
- )
-
- verify(mockExecutor).executeDelayed(eq(mockCallback), anyLong())
+ verify(stateController).setExitAnimationsRunning(true)
}
@Test
@@ -112,10 +103,7 @@
verify(mockStartAnimator, never()).cancel()
- controller.wakeUp(
- doneCallback = mock(),
- executor = mock(),
- )
+ controller.wakeUp()
// Verify that we cancelled the start animator in favor of the exit
// animator.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 47b7d49..8786520 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -41,8 +41,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.complication.ComplicationHostViewController;
import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index c97eedb..d99f0da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -25,7 +25,6 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -500,19 +499,15 @@
true /*shouldShowComplication*/);
mMainExecutor.runAllReady();
- final Runnable callback = mock(Runnable.class);
- mService.onWakeUp(callback);
- mMainExecutor.runAllReady();
- verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor);
+ mService.onWakeUp();
+ verify(mDreamOverlayContainerViewController).wakeUp();
verify(mDreamOverlayCallbackController).onWakeUp();
}
@Test
public void testWakeUpBeforeStartDoesNothing() {
- final Runnable callback = mock(Runnable.class);
- mService.onWakeUp(callback);
- mMainExecutor.runAllReady();
- verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor);
+ mService.onWakeUp();
+ verify(mDreamOverlayContainerViewController, never()).wakeUp();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 1a89076..3f9b198 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -28,6 +28,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.graphics.Region;
import android.testing.AndroidTestingRunner;
@@ -39,10 +40,12 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dreams.touch.scrim.ScrimController;
import com.android.systemui.dreams.touch.scrim.ScrimManager;
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.settings.FakeUserTracker;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -57,6 +60,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
import java.util.Optional;
@SmallTest
@@ -100,21 +104,34 @@
@Mock
UiEventLogger mUiEventLogger;
+ @Mock
+ LockPatternUtils mLockPatternUtils;
+
+ FakeUserTracker mUserTracker;
+
private static final float TOUCH_REGION = .3f;
private static final int SCREEN_WIDTH_PX = 1024;
private static final int SCREEN_HEIGHT_PX = 100;
private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100);
+ private static final UserInfo CURRENT_USER_INFO = new UserInfo(
+ 10,
+ /* name= */ "user10",
+ /* flags= */ 0
+ );
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mUserTracker = new FakeUserTracker();
mTouchHandler = new BouncerSwipeTouchHandler(
mScrimManager,
Optional.of(mCentralSurfaces),
mNotificationShadeWindowController,
mValueAnimatorCreator,
mVelocityTrackerFactory,
+ mLockPatternUtils,
+ mUserTracker,
mFlingAnimationUtils,
mFlingAnimationUtilsClosing,
TOUCH_REGION,
@@ -126,6 +143,9 @@
when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker);
when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS);
+ when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(true);
+
+ mUserTracker.set(Collections.singletonList(CURRENT_USER_INFO), 0);
}
/**
@@ -265,6 +285,32 @@
verifyScroll(.7f, Direction.DOWN, true, gestureListener);
}
+ /**
+ * Makes sure the expansion amount is proportional to (1 - scroll).
+ */
+ @Test
+ public void testSwipeUp_keyguardNotSecure_doesNotExpand() {
+ when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(false);
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+ ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+ final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
+
+ final float distanceY = SCREEN_HEIGHT_PX * 0.3f;
+ final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX, 0);
+ final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX - distanceY, 0);
+
+ reset(mScrimController);
+ assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
+ .isTrue();
+ // We should not expand since the keyguard is not secure
+ verify(mScrimController, never()).expand(any());
+ }
+
private void verifyScroll(float percent, Direction direction,
boolean isBouncerInitiallyShowing, GestureDetector.OnGestureListener gestureListener) {
final float distanceY = SCREEN_HEIGHT_PX * percent;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index c9470bb..3383516 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
@@ -43,7 +44,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -99,6 +100,7 @@
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
private lateinit var dockManager: DockManagerFake
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
private lateinit var underTest: CustomizationProvider
private lateinit var testScope: TestScope
@@ -112,6 +114,7 @@
whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper)
dockManager = DockManagerFake()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
underTest = CustomizationProvider()
val testDispatcher = UnconfinedTestDispatcher()
@@ -199,6 +202,7 @@
logger = logger,
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
+ biometricSettingsRepository = biometricSettingsRepository,
backgroundDispatcher = testDispatcher,
appContext = mContext,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index 2230841..9a2936e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -385,8 +385,6 @@
// We expect that we've set the surface behind to alpha = 0f since we're not interactive.
assertEquals(0f, params.alpha)
assertTrue(params.matrix.isIdentity)
- assertEquals("Wallpaper surface was expected to have opacity 0",
- 0f, captorWp.getLastValue().alpha)
verifyNoMoreInteractions(surfaceTransactionApplier)
}
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 8bb6152..b0c1a34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -86,6 +86,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
@@ -124,6 +125,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.Flow;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -184,6 +188,9 @@
/** Most recent value passed to {@link KeyguardStateController#notifyKeyguardGoingAway}. */
private boolean mKeyguardGoingAway = false;
+ private @Mock CoroutineDispatcher mDispatcher;
+ private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
+
private FakeFeatureFlags mFeatureFlags;
private int mInitialUserId;
@@ -200,6 +207,8 @@
final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
when(testViewRoot.getView()).thenReturn(mock(View.class));
when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
+ when(mDreamingToLockscreenTransitionViewModel.getDreamOverlayAlpha())
+ .thenReturn(mock(Flow.class));
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mViewMediator, mKeyguardBypassController,
@@ -250,6 +259,7 @@
}
@Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() {
// GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady();
@@ -810,7 +820,9 @@
mFeatureFlags,
mSecureSettings,
mSystemSettings,
- mSystemClock);
+ mSystemClock,
+ mDispatcher,
+ () -> mDreamingToLockscreenTransitionViewModel);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
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 eb97022..b4bd473 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -67,7 +67,10 @@
resourceTrimmer =
ResourceTrimmer(
keyguardInteractor,
- KeyguardTransitionInteractor(keyguardTransitionRepository),
+ KeyguardTransitionInteractor(
+ keyguardTransitionRepository,
+ testScope.backgroundScope
+ ),
globalWindowManager,
testScope.backgroundScope,
testDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index f8cb408..1815ea9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance
+import android.app.Activity
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -24,6 +25,7 @@
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -75,6 +77,7 @@
@Mock private lateinit var component: ControlsComponent
@Mock private lateinit var controlsController: ControlsController
@Mock private lateinit var controlsListingController: ControlsListingController
+ @Mock private lateinit var controlsUiController: ControlsUiController
@Mock private lateinit var controlsServiceInfo: ControlsServiceInfo
@Captor
private lateinit var callbackCaptor:
@@ -98,6 +101,8 @@
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController())
.thenReturn(Optional.of(controlsListingController))
+ whenever(controlsUiController.resolveActivity()).thenReturn(FakeActivity::class.java)
+ whenever(component.getControlsUiController()).thenReturn(Optional.of(controlsUiController))
if (hasPanels) {
whenever(controlsServiceInfo.panelActivity).thenReturn(mock())
}
@@ -178,4 +183,6 @@
)
job.cancel()
}
+
+ private class FakeActivity : Activity()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
new file mode 100644
index 0000000..7941a23
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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.keyguard.data.quickaffordance
+
+import android.content.Intent
+import android.net.Uri
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardQuickAffordanceConfigTest : SysuiTestCase() {
+
+ @Test
+ fun appStoreIntent() {
+ overrideResource(R.string.config_appStorePackageName, "app.store.package.name")
+ overrideResource(R.string.config_appStoreAppLinkTemplate, "prefix?id=\$packageName")
+ val packageName = "com.app.package.name"
+
+ val intent = KeyguardQuickAffordanceConfig.appStoreIntent(context, packageName)
+
+ assertThat(intent).isNotNull()
+ assertThat(intent?.`package`).isEqualTo("app.store.package.name")
+ assertThat(intent?.action).isEqualTo(Intent.ACTION_VIEW)
+ assertThat(intent?.data).isEqualTo(Uri.parse("prefix?id=$packageName"))
+ }
+
+ @Test
+ fun appStoreIntent_packageNameNotConfigured_returnNull() {
+ overrideResource(R.string.config_appStorePackageName, "")
+ overrideResource(R.string.config_appStoreAppLinkTemplate, "prefix?id=\$packageName")
+ val packageName = "com.app.package.name"
+
+ val intent = KeyguardQuickAffordanceConfig.appStoreIntent(context, packageName)
+
+ assertThat(intent).isNull()
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun appStoreIntent_packageNameMisconfigured_throwsIllegalStateException() {
+ overrideResource(R.string.config_appStorePackageName, "app.store.package.name")
+ overrideResource(
+ R.string.config_appStoreAppLinkTemplate,
+ "prefix?id=\$misconfiguredPackageName"
+ )
+ val packageName = "com.app.package.name"
+
+ KeyguardQuickAffordanceConfig.appStoreIntent(context, packageName)
+ }
+
+ @Test
+ fun appStoreIntent_linkTemplateNotConfigured_returnNull() {
+ overrideResource(R.string.config_appStorePackageName, "app.store.package.name")
+ overrideResource(R.string.config_appStoreAppLinkTemplate, "")
+ val packageName = "com.app.package.name"
+
+ val intent = KeyguardQuickAffordanceConfig.appStoreIntent(context, packageName)
+
+ assertThat(intent).isNull()
+ }
+
+ @Test
+ fun appStoreIntent_appPackageNameNull_returnNull() {
+ overrideResource(R.string.config_appStorePackageName, "app.store.package.name")
+ overrideResource(R.string.config_appStoreAppLinkTemplate, "prefix?id=\$packageName")
+
+ val intent = KeyguardQuickAffordanceConfig.appStoreIntent(context, null)
+
+ assertThat(intent).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 26c0ea4..7510373 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -53,7 +53,7 @@
MockitoAnnotations.initMocks(this)
whenever(controller.intent).thenReturn(INTENT_1)
- underTest = QrCodeScannerKeyguardQuickAffordanceConfig(mock(), controller)
+ underTest = QrCodeScannerKeyguardQuickAffordanceConfig(context, controller)
}
@Test
@@ -77,22 +77,21 @@
}
@Test
- fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() =
- runBlockingTest {
- whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
- var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
- val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
- val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
- verify(controller).addCallback(callbackCaptor.capture())
+ fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = runBlockingTest {
+ whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+ var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+ val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+ val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+ verify(controller).addCallback(callbackCaptor.capture())
- whenever(controller.intent).thenReturn(INTENT_2)
- callbackCaptor.value.onQRCodeScannerActivityChanged()
+ whenever(controller.intent).thenReturn(INTENT_2)
+ callbackCaptor.value.onQRCodeScannerActivityChanged()
- assertVisibleState(latest)
+ assertVisibleState(latest)
- job.cancel()
- verify(controller).removeCallback(callbackCaptor.value)
- }
+ job.cancel()
+ verify(controller).removeCallback(callbackCaptor.value)
+ }
@Test
fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 3ea74e5..92ec9a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -39,13 +39,14 @@
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -215,7 +216,7 @@
)
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
val keyguardTransitionInteractor =
- KeyguardTransitionInteractor(keyguardTransitionRepository)
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
return DeviceEntryFaceAuthRepositoryImpl(
mContext,
fmOverride,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 6af1220..80700e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -24,16 +24,19 @@
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -82,7 +85,8 @@
bouncerRepository = FakeKeyguardBouncerRepository()
faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest =
SystemUIKeyguardFaceAuthInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index a4f19b4..4b09468 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -22,12 +22,12 @@
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 5de24e4..f63be61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -292,7 +292,8 @@
scope = testScope.backgroundScope,
transitionInteractor =
KeyguardTransitionInteractor(
- repository = keyguardTransitionRepository,
+ keyguardTransitionRepository,
+ testScope.backgroundScope
),
repository = keyguardRepository,
logger = logger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 8f6bbc9..8540bf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
@@ -235,6 +236,7 @@
@JvmField @Parameter(4) var startActivity: Boolean = false
private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig
private lateinit var dockManager: DockManagerFake
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
private lateinit var userTracker: UserTracker
@Before
@@ -246,6 +248,7 @@
homeControls =
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS)
dockManager = DockManagerFake()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
val quickAccessWallet =
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
@@ -333,6 +336,7 @@
logger = logger,
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
+ biometricSettingsRepository = biometricSettingsRepository,
backgroundDispatcher = testDispatcher,
appContext = mContext,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index a087c35..a0c5a75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -40,6 +40,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
@@ -94,6 +95,7 @@
private lateinit var qrCodeScanner: FakeKeyguardQuickAffordanceConfig
private lateinit var featureFlags: FakeFeatureFlags
private lateinit var dockManager: DockManagerFake
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Before
fun setUp() {
@@ -116,6 +118,7 @@
testScope = TestScope(testDispatcher)
dockManager = DockManagerFake()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
val localUserSelectionManager =
KeyguardQuickAffordanceLocalUserSelectionManager(
@@ -197,6 +200,7 @@
logger = logger,
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
+ biometricSettingsRepository = biometricSettingsRepository,
backgroundDispatcher = testDispatcher,
appContext = context,
)
@@ -310,6 +314,24 @@
}
@Test
+ fun quickAffordance_hiddenWhenUserIsInLockdownMode() =
+ testScope.runTest {
+ biometricSettingsRepository.setIsUserInLockdown(true)
+ quickAccessWallet.setState(
+ KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+ icon = ICON,
+ )
+ )
+
+ val collectedValue by
+ collectLastValue(
+ underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
+ )
+
+ assertThat(collectedValue).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
+ }
+
+ @Test
fun quickAffordance_bottomStartAffordanceHiddenWhileDozing() =
testScope.runTest {
repository.setIsDozing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index d66e420..fa4941c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -27,11 +27,14 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
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.OFF
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -46,11 +49,12 @@
private lateinit var underTest: KeyguardTransitionInteractor
private lateinit var repository: FakeKeyguardTransitionRepository
+ private val testScope = TestScope()
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- underTest = KeyguardTransitionInteractor(repository)
+ underTest = KeyguardTransitionInteractor(repository, testScope.backgroundScope)
}
@Test
@@ -108,17 +112,17 @@
}
@Test
- fun keyguardStateTests() = runTest {
+ fun finishedKeyguardStateTests() = testScope.runTest {
val finishedSteps by collectValues(underTest.finishedKeyguardState)
-
+ runCurrent()
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, PRIMARY_BOUNCER, 0f, STARTED))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
steps.forEach {
@@ -126,7 +130,29 @@
runCurrent()
}
- assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD))
+ assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD))
+ }
+
+ @Test
+ fun startedKeyguardStateTests() = testScope.runTest {
+ val finishedSteps by collectValues(underTest.startedKeyguardState)
+ runCurrent()
+ val steps = mutableListOf<TransitionStep>()
+
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
+ steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
+
+ steps.forEach {
+ repository.sendTransitionStep(it)
+ runCurrent()
+ }
+
+ assertThat(finishedSteps).isEqualTo(listOf(OFF, PRIMARY_BOUNCER, AOD, GONE))
}
@Test
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 c53d430..50075b5 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
@@ -20,9 +20,9 @@
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
@@ -108,7 +108,8 @@
keyguardInteractor = createKeyguardInteractor(),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromLockscreenTransitionInteractor.start()
@@ -117,7 +118,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromDreamingTransitionInteractor.start()
@@ -126,7 +128,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromAodTransitionInteractor.start()
@@ -135,7 +138,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromGoneTransitionInteractor.start()
@@ -144,7 +148,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromDozingTransitionInteractor.start()
@@ -153,7 +158,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromOccludedTransitionInteractor.start()
@@ -162,7 +168,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromAlternateBouncerTransitionInteractor.start()
@@ -171,48 +178,14 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
keyguardSecurityModel = keyguardSecurityModel,
)
fromPrimaryBouncerTransitionInteractor.start()
}
@Test
- fun dreamingToLockscreen() =
- testScope.runTest {
- // GIVEN a device is dreaming
- keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setWakefulnessModel(startingToWake())
- runCurrent()
-
- // GIVEN a prior transition has run to DREAMING
- runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
-
- // WHEN doze is complete
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
- )
- // AND dreaming has stopped
- keyguardRepository.setDreamingWithOverlay(false)
- advanceUntilIdle()
- // AND then occluded has stopped
- keyguardRepository.setKeyguardOccluded(false)
- advanceUntilIdle()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
- }
- // THEN a transition to BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
fun lockscreenToPrimaryBouncerViaBouncerShowingCall() =
testScope.runTest {
// GIVEN a device that has at least woken up
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 4440946..08e99dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.LightRevealScrim
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
@@ -45,7 +46,7 @@
private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
private val keyguardTransitionInteractor =
- KeyguardTransitionInteractor(fakeKeyguardTransitionRepository)
+ KeyguardTransitionInteractor(fakeKeyguardTransitionRepository, TestScope().backgroundScope)
private lateinit var underTest: LightRevealScrimInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index cdd06ac..a341346 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -25,11 +25,12 @@
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.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.util.mockito.mock
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -42,13 +43,12 @@
class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: DreamingToLockscreenTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
- private lateinit var transitionAnimation: KeyguardTransitionAnimationFlow
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
- underTest = DreamingToLockscreenTransitionViewModel(interactor)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
+ underTest = DreamingToLockscreenTransitionViewModel(interactor, mock())
}
@Test
@@ -60,17 +60,15 @@
val job =
underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
- // Should start running here...
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
repository.sendTransitionStep(step(0.6f))
- // ...up to here
repository.sendTransitionStep(step(0.8f))
repository.sendTransitionStep(step(1f))
- assertThat(values.size).isEqualTo(5)
+ assertThat(values.size).isEqualTo(7)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
index 40511a0..694539b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = GoneToDreamingTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index a493b1d..29886d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
@@ -107,6 +108,7 @@
private lateinit var quickAccessWalletAffordanceConfig: FakeKeyguardQuickAffordanceConfig
private lateinit var qrCodeScannerAffordanceConfig: FakeKeyguardQuickAffordanceConfig
private lateinit var dockManager: DockManagerFake
+ private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Before
fun setUp() {
@@ -123,6 +125,7 @@
qrCodeScannerAffordanceConfig =
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
dockManager = DockManagerFake()
+ biometricSettingsRepository = FakeBiometricSettingsRepository()
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(
@@ -209,6 +212,7 @@
transitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
repository = repository,
logger = UiEventLoggerFake(),
@@ -233,6 +237,7 @@
logger = logger,
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
+ biometricSettingsRepository = biometricSettingsRepository,
backgroundDispatcher = testDispatcher,
appContext = mContext,
),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index c98058d..ea17751 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToDreamingTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 031b7fb..bf56a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToOccludedTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index c7ff882..34da26e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = OccludedToLockscreenTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index db251a0..f88b71d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -20,9 +20,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -33,6 +33,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -54,7 +55,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest =
PrimaryBouncerToGoneTransitionViewModel(
interactor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 07f7c15..2aff90c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -63,6 +63,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -146,7 +147,7 @@
debugLogger,
mediaFlags,
keyguardUpdateMonitor,
- KeyguardTransitionInteractor(repository = transitionRepository),
+ KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
)
verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 7b673bc..f6075ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -2420,7 +2420,6 @@
@Test
fun playTurbulenceNoise_finishesAfterDuration() {
- fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true)
val semanticActions =
@@ -2452,6 +2451,29 @@
}
@Test
+ fun playTurbulenceNoise_whenPlaybackStateIsNotPlaying_doesNotPlayTurbulence() {
+ fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true)
+
+ val semanticActions =
+ MediaButton(
+ custom0 =
+ MediaAction(
+ icon = null,
+ action = {},
+ contentDescription = "custom0",
+ background = null
+ ),
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.action0.callOnClick()
+
+ assertThat(turbulenceNoiseView.visibility).isEqualTo(View.INVISIBLE)
+ }
+
+ @Test
fun outputSwitcher_hasCustomIntent_openOverLockscreen() {
// When the device for a media player has an intent that opens over lockscreen
val pendingIntent = mock(PendingIntent::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 6d8c9b1..7df54d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -280,6 +280,50 @@
}
@Test
+ public void onBindViewHolder_bindConnectedRemoteDeviceWithOnGoingSession_verifyView() {
+ when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
+ ImmutableList.of());
+ when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
+ assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void onBindViewHolder_bindConnectedRemoteDeviceWithHostOnGoingSession_verifyView() {
+ when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
+ when(mMediaDevice1.isHostForOngoingSession()).thenReturn(true);
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
+ ImmutableList.of());
+ when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ .onCreateViewHolder(new LinearLayout(mContext), 0);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
+ assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mEndClickIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
public void onBindViewHolder_bindConnectedDeviceWithMutingExpectedDeviceExist_verifyView() {
when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true);
when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
index 9dba9b5..f8971fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -136,7 +136,10 @@
@After
public void tearDown() {
- mMediaOutputBroadcastDialog.dismissDialog();
+ if (mMediaOutputBroadcastDialog.mAlertDialog != null){
+ mMediaOutputBroadcastDialog.mAlertDialog.dismiss();
+ }
+ mMediaOutputBroadcastDialog.dismiss();
}
@Test
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 f1bbd84..f25cd24 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
@@ -5,14 +5,15 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.mediaprojection.appselector.data.RecentTask
import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@@ -27,23 +28,28 @@
private val callerPackageName = "com.test.caller"
private val callerComponentName = ComponentName(callerPackageName, "Caller")
- private val hostUserHandle = UserHandle.of(123)
- private val otherUserHandle = UserHandle.of(456)
+ private val personalUserHandle = UserHandle.of(123)
+ private val workUserHandle = UserHandle.of(456)
private val view: MediaProjectionAppSelectorView = mock()
- private val featureFlags: FeatureFlags = mock()
+ private val policyResolver: ScreenCaptureDevicePolicyResolver = mock()
private val controller =
MediaProjectionAppSelectorController(
taskListProvider,
view,
- featureFlags,
- hostUserHandle,
+ policyResolver,
+ personalUserHandle,
scope,
appSelectorComponentName,
callerPackageName
)
+ @Before
+ fun setup() {
+ givenCaptureAllowed(isAllow = true)
+ }
+
@Test
fun initNoRecentTasks_bindsEmptyList() {
taskListProvider.tasks = emptyList()
@@ -132,73 +138,57 @@
}
@Test
- fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsAllTasks() {
- givenEnterprisePoliciesFeatureFlag(enabled = false)
-
+ fun initRecentTasksWithAppSelectorTasks_withEnterprisePolicies_bindsAllTasks() {
val tasks =
listOf(
- createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
)
taskListProvider.tasks = tasks
controller.init()
- // TODO (b/263950746): Cross-profile filtering is removed for now. This should be brought
- // back with the future fix
verify(view)
.bind(
listOf(
- createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
)
)
}
@Test
- fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesEnabled_bindsAllTasks() {
- givenEnterprisePoliciesFeatureFlag(enabled = true)
-
+ fun initRecentTasksWithAppSelectorTasks_withEnterprisePolicies_blocksAllTasks() {
val tasks =
listOf(
- createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
+ createRecentTask(taskId = 1, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 2, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 3, userId = personalUserHandle.identifier),
+ createRecentTask(taskId = 4, userId = workUserHandle.identifier),
+ createRecentTask(taskId = 5, userId = personalUserHandle.identifier),
)
taskListProvider.tasks = tasks
+ givenCaptureAllowed(isAllow = false)
controller.init()
- // TODO(b/233348916) should filter depending on the policies
- verify(view)
- .bind(
- listOf(
- createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
- createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
- createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
- )
- )
+ verify(view).bind(emptyList())
}
- private fun givenEnterprisePoliciesFeatureFlag(enabled: Boolean) {
- whenever(featureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES))
- .thenReturn(enabled)
+ private fun givenCaptureAllowed(isAllow: Boolean) {
+ whenever(policyResolver.isScreenCaptureAllowed(any(), any())).thenReturn(isAllow)
}
private fun createRecentTask(
taskId: Int,
topActivityComponent: ComponentName? = null,
- userId: Int = hostUserHandle.identifier
+ userId: Int = personalUserHandle.identifier
): RecentTask {
return RecentTask(
taskId = taskId,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
index e8b6f9b..c63efa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
@@ -406,28 +406,6 @@
isHostInWorkProfile = true,
isTargetInWorkProfile = true,
personalScreenCaptureDisabled = true,
- workScreenCaptureDisabled = false,
- disallowShareIntoManagedProfile = false
- ),
- expectedScreenCaptureAllowed = true,
- ),
- IsScreenCaptureAllowedTestCase(
- given =
- Preconditions(
- isHostInWorkProfile = true,
- isTargetInWorkProfile = true,
- personalScreenCaptureDisabled = true,
- workScreenCaptureDisabled = false,
- disallowShareIntoManagedProfile = true
- ),
- expectedScreenCaptureAllowed = true,
- ),
- IsScreenCaptureAllowedTestCase(
- given =
- Preconditions(
- isHostInWorkProfile = true,
- isTargetInWorkProfile = true,
- personalScreenCaptureDisabled = true,
workScreenCaptureDisabled = true,
disallowShareIntoManagedProfile = false
),
@@ -626,26 +604,6 @@
Preconditions(
isHostInWorkProfile = true,
personalScreenCaptureDisabled = true,
- workScreenCaptureDisabled = false,
- disallowShareIntoManagedProfile = false
- ),
- expectedScreenCaptureCompletelyDisabled = false,
- ),
- IsScreenCaptureCompletelyDisabledTestCase(
- given =
- Preconditions(
- isHostInWorkProfile = true,
- personalScreenCaptureDisabled = true,
- workScreenCaptureDisabled = false,
- disallowShareIntoManagedProfile = true
- ),
- expectedScreenCaptureCompletelyDisabled = false,
- ),
- IsScreenCaptureCompletelyDisabledTestCase(
- given =
- Preconditions(
- isHostInWorkProfile = true,
- personalScreenCaptureDisabled = true,
workScreenCaptureDisabled = true,
disallowShareIntoManagedProfile = false
),
@@ -686,7 +644,8 @@
"personal screen capture disabled = ${given.personalScreenCaptureDisabled}, " +
"work screen capture disabled = ${given.workScreenCaptureDisabled}, " +
"disallow share into managed profile = ${given.disallowShareIntoManagedProfile}, " +
- "expected screen capture completely disabled = $expectedScreenCaptureCompletelyDisabled"
+ "expected screen capture completely disabled = " +
+ "$expectedScreenCaptureCompletelyDisabled"
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
index 19f9960..9e54224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
@@ -99,6 +99,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = keyguardTransitionRepository,
+ scope = testScope.backgroundScope
),
falsingManager = falsingManager,
shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index 204077b..a76af8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -244,8 +244,38 @@
// endregion
// region showNoteTask
+ fun showNoteTaskAsUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
+ val user10 = UserHandle.of(/* userId= */ 10)
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(
+ entryPoint = TAIL_BUTTON,
+ isKeyguardLocked = true,
+ user = user10,
+ )
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+
+ createNoteTaskController()
+ .showNoteTaskAsUser(entryPoint = expectedInfo.entryPoint!!, user = user10)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_CREATE_NOTE)
+ hasPackage(NOTE_TASK_PACKAGE_NAME)
+ hasFlags(FLAG_ACTIVITY_NEW_TASK)
+ hasFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
+ hasFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
+ extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
+ }
+ assertThat(userCaptor.value).isEqualTo(user10)
+ verify(eventLogger).logNoteTaskOpened(expectedInfo)
+ verifyZeroInteractions(bubbles)
+ }
+
@Test
- fun showNoteTask_keyguardIsLocked_shouldStartActivityAndLogUiEvent() {
+ fun showNoteTask_keyguardIsLocked_notesIsClosed_shouldStartActivityAndLogUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
@@ -269,6 +299,59 @@
}
@Test
+ fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() {
+ val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+ whenever(activityManager.getRunningTasks(anyInt()))
+ .thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ val intentCaptor = argumentCaptor<Intent>()
+ val userCaptor = argumentCaptor<UserHandle>()
+ verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
+ assertThat(intentCaptor.value).run {
+ hasAction(ACTION_MAIN)
+ categories().contains(CATEGORY_HOME)
+ hasFlags(FLAG_ACTIVITY_NEW_TASK)
+ }
+ assertThat(userCaptor.value).isEqualTo(userTracker.userHandle)
+ verify(eventLogger).logNoteTaskClosed(expectedInfo)
+ verifyZeroInteractions(bubbles)
+ }
+
+ @Test
+ fun showNoteTask_keyguardIsUnlocked_noteIsClosed_shouldStartBubblesWithoutLoggingUiEvent() {
+ val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ // Context package name used to create bubble icon from drawable resource id
+ verify(context, atLeastOnce()).packageName
+ verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
+ verifyZeroInteractions(eventLogger)
+ }
+
+ @Test
+ fun showNoteTask_keyguardIsUnlocked_noteIsOpen_shouldStartBubblesWithoutLoggingUiEvent() {
+ val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(activityManager.getRunningTasks(anyInt()))
+ .thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ // Context package name used to create bubble icon from drawable resource id
+ verify(context, atLeastOnce()).packageName
+ verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
+ verifyZeroInteractions(eventLogger)
+ }
+
+ @Test
fun showNoteTask_defaultUserSet_shouldStartActivityWithExpectedUserAndLogUiEvent() {
whenever(secureSettings.getInt(eq(Settings.Secure.DEFAULT_NOTE_TASK_PROFILE), any()))
.thenReturn(10)
@@ -307,70 +390,6 @@
}
@Test
- fun showNoteTaskWithUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
- val user10 = UserHandle.of(/* userId= */ 10)
- val expectedInfo =
- NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true, user = user10)
- whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
-
- createNoteTaskController()
- .showNoteTaskAsUser(entryPoint = expectedInfo.entryPoint!!, user = user10)
-
- val intentCaptor = argumentCaptor<Intent>()
- val userCaptor = argumentCaptor<UserHandle>()
- verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
- assertThat(intentCaptor.value).run {
- hasAction(ACTION_CREATE_NOTE)
- hasPackage(NOTE_TASK_PACKAGE_NAME)
- hasFlags(FLAG_ACTIVITY_NEW_TASK)
- hasFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
- hasFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
- extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
- }
- assertThat(userCaptor.value).isEqualTo(user10)
- verify(eventLogger).logNoteTaskOpened(expectedInfo)
- verifyZeroInteractions(bubbles)
- }
-
- @Test
- fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() {
- val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
- whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
- whenever(activityManager.getRunningTasks(anyInt()))
- .thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
-
- createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
-
- val intentCaptor = argumentCaptor<Intent>()
- val userCaptor = argumentCaptor<UserHandle>()
- verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
- assertThat(intentCaptor.value).run {
- hasAction(ACTION_MAIN)
- categories().contains(CATEGORY_HOME)
- hasFlags(FLAG_ACTIVITY_NEW_TASK)
- }
- assertThat(userCaptor.value).isEqualTo(userTracker.userHandle)
- verify(eventLogger).logNoteTaskClosed(expectedInfo)
- verifyZeroInteractions(bubbles)
- }
-
- @Test
- fun showNoteTask_keyguardIsUnlocked_shouldStartBubblesWithoutLoggingUiEvent() {
- val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false)
- whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
- whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
-
- createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
-
- // Context package name used to create bubble icon from drawable resource id
- verify(context, atLeastOnce()).packageName
- verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
- verifyZeroInteractions(eventLogger)
- }
-
- @Test
fun showNoteTask_bubblesIsNull_shouldDoNothing() {
createNoteTaskController(bubbles = null).showNoteTask(entryPoint = TAIL_BUTTON)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
index 3435450..24f39d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
@@ -16,37 +16,47 @@
package com.android.systemui.notetask
import android.os.UserHandle
-import android.test.suitebuilder.annotation.SmallTest
-import androidx.test.runner.AndroidJUnit4
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
/** atest SystemUITests:NoteTaskInfoTest */
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(AndroidTestingRunner::class)
internal class NoteTaskInfoTest : SysuiTestCase() {
- private fun createNoteTaskInfo(): NoteTaskInfo =
- NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID, UserHandle.of(0))
-
@Test
fun launchMode_keyguardLocked_launchModeActivity() {
- val underTest = createNoteTaskInfo().copy(isKeyguardLocked = true)
+ val underTest = DEFAULT_INFO.copy(isKeyguardLocked = true)
assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity)
}
@Test
- fun launchMode_keyguardUnlocked_launchModeActivity() {
- val underTest = createNoteTaskInfo().copy(isKeyguardLocked = false)
+ fun launchMode_multiWindowMode_launchModeActivity() {
+ val underTest = DEFAULT_INFO.copy(entryPoint = WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE)
+
+ assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity)
+ }
+
+ @Test
+ fun launchMode_keyguardUnlocked_launchModeAppBubble() {
+ val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false)
assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.AppBubble)
}
private companion object {
- const val NOTES_PACKAGE_NAME = "com.android.note.app"
- const val NOTES_UID = 123456
+
+ val DEFAULT_INFO =
+ NoteTaskInfo(
+ packageName = "com.android.note.app",
+ uid = 123456,
+ user = UserHandle.of(0),
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index 4526580..58c762e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -40,7 +40,6 @@
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.notetask.NoteTaskInfoResolver
-import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
import com.android.systemui.stylus.StylusManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -283,7 +282,7 @@
}
@Test
- fun getPickerScreenState_nodefaultNoteAppSet_shouldReturnDisable() = runTest {
+ fun getPickerScreenState_noDefaultNoteAppSet_shouldReturnDisabled() = runTest {
val underTest = createUnderTest(isEnabled = true)
whenever(
roleManager.getRoleHoldersAsUser(
@@ -293,16 +292,16 @@
)
.thenReturn(emptyList())
- assertThat(underTest.getPickerScreenState())
- .isEqualTo(
- KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- listOf("Select a default notes app to use the notetaking shortcut"),
- actionText = "Select app",
- actionComponentName =
- "${context.packageName}$COMPONENT_NAME_SEPARATOR" +
- "$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
- )
- )
+ val pickerScreenState = underTest.getPickerScreenState()
+ assertThat(pickerScreenState is KeyguardQuickAffordanceConfig.PickerScreenState.Disabled)
+ .isTrue()
+ val disabled = pickerScreenState as KeyguardQuickAffordanceConfig.PickerScreenState.Disabled
+ assertThat(disabled.explanation)
+ .isEqualTo("Select a default notes app to use the notetaking shortcut")
+ assertThat(disabled.actionText).isEqualTo("Select app")
+ assertThat(disabled.actionIntent?.action)
+ .isEqualTo(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE)
+ assertThat(disabled.actionIntent?.`package`).isEqualTo(context.packageName)
}
// endregion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index e0f27de1..e669d06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -481,6 +481,8 @@
int[] widgetIdsArray = {1};
when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mUserManager.isUserUnlocked(any())).thenReturn(true);
+
NotificationChannel channel =
new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID);
@@ -489,8 +491,25 @@
UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1)).updateAppWidget(anyInt(),
- any());
+ verify(mAppWidgetManager, times(1)).updateAppWidget(anyInt(), any());
+ }
+
+ @Test
+ public void testOnNotificationChannelModified_userLocked() {
+ int[] widgetIdsArray = {1};
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ when(mUserManager.isUserUnlocked(any())).thenReturn(false);
+
+ NotificationChannel channel =
+ new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
+ channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID);
+
+ mNoMan.issueChannelModification(TEST_PACKAGE_A,
+ UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
index bb3b3f7..a01394f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -24,7 +24,11 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+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.eq
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
@@ -47,6 +51,8 @@
@RunWith(JUnit4::class)
class PowerRepositoryImplTest : SysuiTestCase() {
+ private val systemClock = FakeSystemClock()
+
@Mock private lateinit var manager: PowerManager
@Mock private lateinit var dispatcher: BroadcastDispatcher
@Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
@@ -62,7 +68,13 @@
isInteractive = true
whenever(manager.isInteractive).then { isInteractive }
- underTest = PowerRepositoryImpl(manager = manager, dispatcher = dispatcher)
+ underTest =
+ PowerRepositoryImpl(
+ manager,
+ context.applicationContext,
+ systemClock,
+ dispatcher,
+ )
}
@Test
@@ -160,6 +172,27 @@
job.cancel()
}
+ @Test
+ fun wakeUp_notifiesPowerManager() {
+ systemClock.setUptimeMillis(345000)
+
+ underTest.wakeUp("fakeWhy", PowerManager.WAKE_REASON_GESTURE)
+
+ val reasonCaptor = argumentCaptor<String>()
+ verify(manager)
+ .wakeUp(eq(345000L), eq(PowerManager.WAKE_REASON_GESTURE), capture(reasonCaptor))
+ assertThat(reasonCaptor.value).contains("fakeWhy")
+ }
+
+ @Test
+ fun wakeUp_usesApplicationPackageName() {
+ underTest.wakeUp("fakeWhy", PowerManager.WAKE_REASON_GESTURE)
+
+ val reasonCaptor = argumentCaptor<String>()
+ verify(manager).wakeUp(any(), any(), capture(reasonCaptor))
+ assertThat(reasonCaptor.value).contains(context.applicationContext.packageName)
+ }
+
private fun verifyRegistered() {
// We must verify with all arguments, even those that are optional because they have default
// values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
index 31d4512..023ed06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -17,9 +17,14 @@
package com.android.systemui.power.domain.interactor
+import android.os.PowerManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
@@ -29,6 +34,9 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(JUnit4::class)
@@ -36,14 +44,25 @@
private lateinit var underTest: PowerInteractor
private lateinit var repository: FakePowerRepository
+ @Mock private lateinit var falsingCollector: FalsingCollector
+ @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
repository =
FakePowerRepository(
initialInteractive = true,
)
- underTest = PowerInteractor(repository = repository)
+ underTest =
+ PowerInteractor(
+ repository,
+ falsingCollector,
+ screenOffAnimationController,
+ statusBarStateController,
+ )
}
@Test
@@ -72,6 +91,40 @@
job.cancel()
}
+ @Test
+ fun wakeUpIfDozing_notDozing_notWoken() {
+ whenever(statusBarStateController.isDozing).thenReturn(false)
+ whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
+
+ underTest.wakeUpIfDozing("why", PowerManager.WAKE_REASON_TAP)
+
+ assertThat(repository.lastWakeWhy).isNull()
+ assertThat(repository.lastWakeReason).isNull()
+ }
+
+ @Test
+ fun wakeUpIfDozing_notAllowed_notWoken() {
+ whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(false)
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+
+ underTest.wakeUpIfDozing("why", PowerManager.WAKE_REASON_TAP)
+
+ assertThat(repository.lastWakeWhy).isNull()
+ assertThat(repository.lastWakeReason).isNull()
+ }
+
+ @Test
+ fun wakeUpIfDozing_dozingAndAllowed_wokenAndFalsingNotified() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+ whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
+
+ underTest.wakeUpIfDozing("testReason", PowerManager.WAKE_REASON_GESTURE)
+
+ assertThat(repository.lastWakeWhy).isEqualTo("testReason")
+ assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
+ verify(falsingCollector).onScreenOnFromTouch()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 87ca9df..fcda5f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -50,10 +50,8 @@
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
-import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.ui.MediaHost;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
@@ -169,9 +167,7 @@
}
@Test
- public void transitionToFullShade_largeScreen_flagEnabled_alphaLargeScreenShadeInterpolator() {
- when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(true);
+ public void transitionToFullShade_largeScreen_alphaLargeScreenShadeInterpolator() {
QSFragment fragment = resumeAndGetFragment();
setIsLargeScreen();
setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE);
@@ -188,25 +184,6 @@
}
@Test
- public void transitionToFullShade_largeScreen_flagDisabled_alphaStandardInterpolator() {
- when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(false);
- QSFragment fragment = resumeAndGetFragment();
- setIsLargeScreen();
- setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE);
- boolean isTransitioningToFullShade = true;
- float transitionProgress = 0.5f;
- float squishinessFraction = 0.5f;
- when(mLargeScreenShadeInterpolator.getQsAlpha(transitionProgress)).thenReturn(123f);
-
- fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
- squishinessFraction);
-
- assertThat(mQsFragmentView.getAlpha())
- .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
- }
-
- @Test
public void
transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
QSFragment fragment = resumeAndGetFragment();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 198ed4a..41240e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -35,7 +35,7 @@
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.LaunchableFrameLayout
+import com.android.systemui.animation.view.LaunchableFrameLayout
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
new file mode 100644
index 0000000..18f3837
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt
@@ -0,0 +1,278 @@
+/*
+ * 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.qs.pipeline.data.repository
+
+import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
+import android.content.pm.ServiceInfo
+import android.os.UserHandle
+import android.service.quicksettings.TileService
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argThat
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Mock private lateinit var context: Context
+ @Mock private lateinit var packageManager: PackageManager
+ @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
+
+ private lateinit var underTest: InstalledTilesComponentRepositoryImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ // Use the default value set in the ServiceInfo
+ whenever(packageManager.getComponentEnabledSetting(any()))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
+
+ // Return empty by default
+ whenever(packageManager.queryIntentServicesAsUser(any(), any<ResolveInfoFlags>(), anyInt()))
+ .thenReturn(emptyList())
+
+ underTest =
+ InstalledTilesComponentRepositoryImpl(
+ context,
+ packageManager,
+ testDispatcher,
+ )
+ }
+
+ @Test
+ fun registersAndUnregistersBroadcastReceiver() =
+ testScope.runTest {
+ val user = 10
+ val job = launch { underTest.getInstalledTilesComponents(user).collect {} }
+ runCurrent()
+
+ verify(context)
+ .registerReceiverAsUser(
+ capture(receiverCaptor),
+ eq(UserHandle.of(user)),
+ any(),
+ nullable(),
+ nullable(),
+ )
+
+ verify(context, never()).unregisterReceiver(receiverCaptor.value)
+
+ job.cancel()
+ runCurrent()
+ verify(context).unregisterReceiver(receiverCaptor.value)
+ }
+
+ @Test
+ fun intentFilterForCorrectActionsAndScheme() =
+ testScope.runTest {
+ val filterCaptor = argumentCaptor<IntentFilter>()
+
+ backgroundScope.launch { underTest.getInstalledTilesComponents(0).collect {} }
+ runCurrent()
+
+ verify(context)
+ .registerReceiverAsUser(
+ any(),
+ any(),
+ capture(filterCaptor),
+ nullable(),
+ nullable(),
+ )
+
+ with(filterCaptor.value) {
+ assertThat(matchAction(Intent.ACTION_PACKAGE_CHANGED)).isTrue()
+ assertThat(matchAction(Intent.ACTION_PACKAGE_ADDED)).isTrue()
+ assertThat(matchAction(Intent.ACTION_PACKAGE_REMOVED)).isTrue()
+ assertThat(matchAction(Intent.ACTION_PACKAGE_REPLACED)).isTrue()
+ assertThat(countActions()).isEqualTo(4)
+
+ assertThat(hasDataScheme("package")).isTrue()
+ assertThat(countDataSchemes()).isEqualTo(1)
+ }
+ }
+
+ @Test
+ fun componentsLoadedOnStart() =
+ testScope.runTest {
+ val userId = 0
+ val resolveInfo =
+ ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true)
+ whenever(
+ packageManager.queryIntentServicesAsUser(
+ matchIntent(),
+ matchFlags(),
+ eq(userId)
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
+
+ val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+
+ assertThat(componentNames).containsExactly(TEST_COMPONENT)
+ }
+
+ @Test
+ fun componentAdded_foundAfterBroadcast() =
+ testScope.runTest {
+ val userId = 0
+ val resolveInfo =
+ ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true)
+
+ val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+ assertThat(componentNames).isEmpty()
+
+ whenever(
+ packageManager.queryIntentServicesAsUser(
+ matchIntent(),
+ matchFlags(),
+ eq(userId)
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
+ getRegisteredReceiver().onReceive(context, Intent(Intent.ACTION_PACKAGE_ADDED))
+
+ assertThat(componentNames).containsExactly(TEST_COMPONENT)
+ }
+
+ @Test
+ fun componentWithoutPermission_notValid() =
+ testScope.runTest {
+ val userId = 0
+ val resolveInfo =
+ ResolveInfo(TEST_COMPONENT, hasPermission = false, defaultEnabled = true)
+ whenever(
+ packageManager.queryIntentServicesAsUser(
+ matchIntent(),
+ matchFlags(),
+ eq(userId)
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
+
+ val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+ assertThat(componentNames).isEmpty()
+ }
+
+ @Test
+ fun componentNotEnabled_notValid() =
+ testScope.runTest {
+ val userId = 0
+ val resolveInfo =
+ ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = false)
+ whenever(
+ packageManager.queryIntentServicesAsUser(
+ matchIntent(),
+ matchFlags(),
+ eq(userId)
+ )
+ )
+ .thenReturn(listOf(resolveInfo))
+
+ val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId))
+ assertThat(componentNames).isEmpty()
+ }
+
+ private fun getRegisteredReceiver(): BroadcastReceiver {
+ verify(context)
+ .registerReceiverAsUser(
+ capture(receiverCaptor),
+ any(),
+ any(),
+ nullable(),
+ nullable(),
+ )
+
+ return receiverCaptor.value
+ }
+
+ companion object {
+ private val INTENT = Intent(TileService.ACTION_QS_TILE)
+ private val FLAGS =
+ ResolveInfoFlags.of(
+ (PackageManager.MATCH_DIRECT_BOOT_AWARE or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
+ PackageManager.GET_SERVICES)
+ .toLong()
+ )
+ private val PERMISSION = BIND_QUICK_SETTINGS_TILE
+
+ private val TEST_COMPONENT = ComponentName("pkg", "cls")
+
+ private fun matchFlags() =
+ argThat<ResolveInfoFlags> { flags -> flags?.value == FLAGS.value }
+ private fun matchIntent() = argThat<Intent> { intent -> intent.action == INTENT.action }
+
+ private fun ResolveInfo(
+ componentName: ComponentName,
+ hasPermission: Boolean,
+ defaultEnabled: Boolean
+ ): ResolveInfo {
+ val applicationInfo = ApplicationInfo().apply { enabled = true }
+ val serviceInfo =
+ ServiceInfo().apply {
+ packageName = componentName.packageName
+ name = componentName.className
+ if (hasPermission) {
+ permission = PERMISSION
+ }
+ enabled = defaultEnabled
+ this.applicationInfo = applicationInfo
+ }
+ val resolveInfo = ResolveInfo()
+ resolveInfo.serviceInfo = serviceInfo
+ return resolveInfo
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index 426ff67..e7ad489 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.qs.external.TileServiceKey
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository
import com.android.systemui.qs.pipeline.data.repository.FakeCustomTileAddedRepository
+import com.android.systemui.qs.pipeline.data.repository.FakeInstalledTilesComponentRepository
import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository
import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
import com.android.systemui.qs.pipeline.domain.model.TileModel
@@ -73,6 +74,7 @@
private val tileSpecRepository: TileSpecRepository = FakeTileSpecRepository()
private val userRepository = FakeUserRepository()
+ private val installedTilesPackageRepository = FakeInstalledTilesComponentRepository()
private val tileFactory = FakeQSFactory(::tileCreator)
private val customTileAddedRepository: CustomTileAddedRepository =
FakeCustomTileAddedRepository()
@@ -100,11 +102,13 @@
featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true)
userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
+
setUserTracker(0)
underTest =
CurrentTilesInteractorImpl(
tileSpecRepository = tileSpecRepository,
+ installedTilesComponentRepository = installedTilesPackageRepository,
userRepository = userRepository,
customTileStatePersister = customTileStatePersister,
tileFactory = tileFactory,
@@ -609,6 +613,40 @@
assertThat((tileA as FakeQSTile).callbacks).containsExactly(callback)
}
+ @Test
+ fun packageNotInstalled_customTileNotVisible() =
+ testScope.runTest(USER_INFO_0) {
+ installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
+
+ val tiles by collectLastValue(underTest.currentTiles)
+
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+
+ assertThat(tiles!!.size).isEqualTo(1)
+ assertThat(tiles!![0].spec).isEqualTo(specs[0])
+ }
+
+ @Test
+ fun packageInstalledLater_customTileAdded() =
+ testScope.runTest(USER_INFO_0) {
+ installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
+
+ val tiles by collectLastValue(underTest.currentTiles)
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC, TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+
+ assertThat(tiles!!.size).isEqualTo(2)
+
+ installedTilesPackageRepository.setInstalledPackagesForUser(
+ USER_INFO_0.id,
+ setOf(TEST_COMPONENT)
+ )
+
+ assertThat(tiles!!.size).isEqualTo(3)
+ assertThat(tiles!![1].spec).isEqualTo(CUSTOM_TILE_SPEC)
+ }
+
private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
this.state = state
this.label = label
@@ -654,6 +692,7 @@
private suspend fun switchUser(user: UserInfo) {
setUserTracker(user.id)
+ installedTilesPackageRepository.setInstalledPackagesForUser(user.id, setOf(TEST_COMPONENT))
userRepository.setSelectedUserInfo(user)
}
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 ee382d3..46ced82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -91,7 +91,7 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
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 0393bef..af40e5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -34,14 +34,14 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
-import com.android.systemui.keyguard.bouncer.domain.interactor.CountDownTimerUtil
-import com.android.systemui.keyguard.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.multishade.data.remoteproxy.MultiShadeInputProxy
@@ -111,8 +111,7 @@
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
- @Mock
- private lateinit var unfoldTransitionProgressProvider:
+ @Mock private lateinit var unfoldTransitionProgressProvider:
Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
@@ -195,6 +194,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
falsingManager = FalsingManagerFake(),
shadeController = shadeController,
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 5ae8ee1..d3ecc3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -27,6 +27,11 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
+import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dock.DockManager
@@ -34,13 +39,8 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
-import com.android.systemui.keyguard.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor
-import com.android.systemui.keyguard.bouncer.domain.interactor.CountDownTimerUtil
-import com.android.systemui.keyguard.data.repository.FakeBouncerMessageRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.multishade.data.remoteproxy.MultiShadeInputProxy
@@ -207,6 +207,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
falsingManager = FalsingManagerFake(),
shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index d7c06a7..f1d56f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -25,22 +25,24 @@
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
import com.android.systemui.util.mockito.eq
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyLong
-import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -54,12 +56,12 @@
@Mock
private lateinit var view: NotificationShadeWindowView
@Mock
- private lateinit var centralSurfaces: CentralSurfaces
- @Mock
private lateinit var dockManager: DockManager
@Mock
private lateinit var falsingManager: FalsingManager
@Mock
+ private lateinit var falsingCollector: FalsingCollector
+ @Mock
private lateinit var ambientDisplayConfiguration: AmbientDisplayConfiguration
@Mock
private lateinit var tunerService: TunerService
@@ -71,7 +73,10 @@
private lateinit var shadeLogger: ShadeLogger
@Mock
private lateinit var userTracker: UserTracker
+ @Mock
+ private lateinit var screenOffAnimationController: ScreenOffAnimationController
+ private lateinit var powerRepository: FakePowerRepository
private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
private lateinit var underTest: PulsingGestureListener
@@ -79,11 +84,18 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
+ powerRepository = FakePowerRepository()
+
underTest = PulsingGestureListener(
view,
falsingManager,
dockManager,
- centralSurfaces,
+ PowerInteractor(
+ powerRepository,
+ falsingCollector,
+ screenOffAnimationController,
+ statusBarStateController,
+ ),
ambientDisplayConfiguration,
statusBarStateController,
shadeLogger,
@@ -92,6 +104,7 @@
dumpManager
)
whenever(dockManager.isDocked).thenReturn(false)
+ whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
}
@Test
@@ -110,8 +123,8 @@
underTest.onSingleTapUp(upEv)
// THEN wake up device if dozing
- verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ assertThat(powerRepository.lastWakeWhy).isNotNull()
+ assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_TAP)
}
@Test
@@ -130,8 +143,8 @@
underTest.onDoubleTapEvent(upEv)
// THEN wake up device if dozing
- verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ assertThat(powerRepository.lastWakeWhy).isNotNull()
+ assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_TAP)
}
@Test
@@ -162,8 +175,8 @@
underTest.onSingleTapUp(upEv)
// THEN the device doesn't wake up
- verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), anyString(), anyInt())
+ assertThat(powerRepository.lastWakeWhy).isNull()
+ assertThat(powerRepository.lastWakeReason).isNull()
}
@Test
@@ -210,8 +223,8 @@
underTest.onDoubleTapEvent(upEv)
// THEN the device doesn't wake up
- verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), anyString(), anyInt())
+ assertThat(powerRepository.lastWakeWhy).isNull()
+ assertThat(powerRepository.lastWakeReason).isNull()
}
@Test
@@ -230,8 +243,8 @@
underTest.onSingleTapUp(upEv)
// THEN the device doesn't wake up
- verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), anyString(), anyInt())
+ assertThat(powerRepository.lastWakeWhy).isNull()
+ assertThat(powerRepository.lastWakeReason).isNull()
}
@Test
@@ -250,8 +263,8 @@
underTest.onDoubleTapEvent(upEv)
// THEN the device doesn't wake up
- verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), anyString(), anyInt())
+ assertThat(powerRepository.lastWakeWhy).isNull()
+ assertThat(powerRepository.lastWakeReason).isNull()
}
fun updateSettings() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index ef66756..00a0567 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -57,6 +57,7 @@
@Mock private lateinit var assistManager: AssistManager
@Mock private lateinit var gutsManager: NotificationGutsManager
@Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var nswvc: NotificationShadeWindowViewController
@Mock private lateinit var display: Display
private lateinit var shadeController: ShadeControllerImpl
@@ -80,6 +81,7 @@
Lazy { assistManager },
Lazy { gutsManager },
)
+ shadeController.setNotificationShadeWindowViewController(nswvc)
shadeController.setNotificationPanelViewController(notificationPanelViewController)
}
@@ -104,4 +106,28 @@
shadeController.animateExpandQs()
verify(notificationPanelViewController).expandToQs()
}
+
+ @Test
+ fun cancelExpansionAndCollapseShade_callsCancelCurrentTouch() {
+ // GIVEN the shade is tracking a touch
+ whenever(notificationPanelViewController.isTracking).thenReturn(true)
+
+ // WHEN cancelExpansionAndCollapseShade is called
+ shadeController.cancelExpansionAndCollapseShade()
+
+ // VERIFY that cancelCurrentTouch is called
+ verify(nswvc).cancelCurrentTouch()
+ }
+
+ @Test
+ fun cancelExpansionAndCollapseShade_doesNotCallAnimateCollapseShade_whenCollapsed() {
+ // GIVEN the shade is tracking a touch
+ whenever(notificationPanelViewController.isTracking).thenReturn(false)
+
+ // WHEN cancelExpansionAndCollapseShade is called
+ shadeController.cancelExpansionAndCollapseShade()
+
+ // VERIFY that cancelCurrentTouch is NOT called
+ verify(nswvc, never()).cancelCurrentTouch()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 20da8a6..2da2e92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -78,6 +78,7 @@
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@@ -387,7 +388,7 @@
whenever(clock.isLayoutRtl).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
- verify(clock).addOnLayoutChangeListener(capture(captor))
+ verify(clock, times(2)).addOnLayoutChangeListener(capture(captor))
captor.value.onLayoutChange(clock, 0, 1, 2, 3, 4, 5, 6, 7)
verify(clock).pivotX = 0f
@@ -400,7 +401,7 @@
whenever(clock.isLayoutRtl).thenReturn(true)
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
- verify(clock).addOnLayoutChangeListener(capture(captor))
+ verify(clock, times(2)).addOnLayoutChangeListener(capture(captor))
captor.value.onLayoutChange(clock, 0, 1, 2, 3, 4, 5, 6, 7)
verify(clock).pivotX = width.toFloat()
@@ -793,7 +794,7 @@
@Test
fun clockPivotYInCenter() {
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
- verify(clock).addOnLayoutChangeListener(capture(captor))
+ verify(clock, times(2)).addOnLayoutChangeListener(capture(captor))
var height = 100
val width = 50
@@ -825,16 +826,17 @@
}
@Test
- fun carrierLeftPaddingIsSetWhenClockLayoutChanges() {
- val width = 200
- whenever(clock.width).thenReturn(width)
- whenever(clock.scaleX).thenReturn(2.57f) // 2.57 comes from qs_header.xml
+ fun carrierStartPaddingIsSetOnClockLayout() {
+ val clockWidth = 200
+ val maxClockScale = context.resources.getFloat(R.dimen.qqs_expand_clock_scale)
+ val expectedStartPadding = (clockWidth * maxClockScale).toInt()
+ whenever(clock.width).thenReturn(clockWidth)
+
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
+ verify(clock, times(2)).addOnLayoutChangeListener(capture(captor))
+ captor.allValues.forEach { clock.executeLayoutChange(0, 0, clockWidth, 0, it) }
- verify(clock).addOnLayoutChangeListener(capture(captor))
- captor.value.onLayoutChange(clock, 0, 0, width, 0, 0, 0, 0, 0)
-
- verify(carrierGroup).setPaddingRelative(514, 0, 0, 0)
+ verify(carrierGroup).setPaddingRelative(expectedStartPadding, 0, 0, 0)
}
@Test
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 cbf5485..a5bd2ae 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
@@ -2,26 +2,16 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.shade.STATE_CLOSED
-import com.android.systemui.shade.STATE_OPEN
import com.android.systemui.shade.STATE_OPENING
import com.android.systemui.shade.ShadeExpansionChangeEvent
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.HeadsUpManager
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -30,10 +20,6 @@
@Mock private lateinit var scrimController: ScrimController
@Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
- @Mock private lateinit var headsUpManager: HeadsUpManager
- @Mock private lateinit var featureFlags: FeatureFlags
- private val configurationController = FakeConfigurationController()
private lateinit var controller: ScrimShadeTransitionController
@@ -41,131 +27,25 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
context.ensureTestableResources()
- controller =
- ScrimShadeTransitionController(
- configurationController,
- dumpManager,
- scrimController,
- context.resources,
- statusBarStateController,
- headsUpManager,
- featureFlags)
+ controller = ScrimShadeTransitionController(dumpManager, scrimController)
controller.onPanelStateChanged(STATE_OPENING)
}
@Test
- fun onPanelExpansionChanged_inSingleShade_setsFractionEqualToEventFraction() {
- setSplitShadeEnabled(false)
-
+ fun onPanelExpansionChanged_setsFractionEqualToEventFraction() {
controller.onPanelExpansionChanged(EXPANSION_EVENT)
verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
}
- @Test
- fun onPanelExpansionChanged_inSplitShade_unlockedShade_setsFractionBasedOnDragDownAmount() {
- whenever(statusBarStateController.currentOrUpcomingState).thenReturn(StatusBarState.SHADE)
- val scrimShadeTransitionDistance =
- context.resources.getDimensionPixelSize(R.dimen.split_shade_scrim_transition_distance)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- val expectedFraction = EXPANSION_EVENT.dragDownPxAmount / scrimShadeTransitionDistance
- verify(scrimController).setRawPanelExpansionFraction(expectedFraction)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_largeDragDownAmount_fractionIsNotGreaterThan1() {
- whenever(statusBarStateController.currentOrUpcomingState).thenReturn(StatusBarState.SHADE)
- val scrimShadeTransitionDistance =
- context.resources.getDimensionPixelSize(R.dimen.split_shade_scrim_transition_distance)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(
- EXPANSION_EVENT.copy(dragDownPxAmount = 100f * scrimShadeTransitionDistance))
-
- verify(scrimController).setRawPanelExpansionFraction(1f)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_negativeDragDownAmount_fractionIsNotLessThan0() {
- whenever(statusBarStateController.currentOrUpcomingState).thenReturn(StatusBarState.SHADE)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT.copy(dragDownPxAmount = -100f))
-
- verify(scrimController).setRawPanelExpansionFraction(0f)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_onLockedShade_setsFractionEqualToEventFraction() {
- whenever(statusBarStateController.currentOrUpcomingState)
- .thenReturn(StatusBarState.SHADE_LOCKED)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_flagTrue_setsFractionEqualToEventFraction() {
- whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(true)
- whenever(statusBarStateController.currentOrUpcomingState)
- .thenReturn(StatusBarState.SHADE)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_onKeyguard_setsFractionEqualToEventFraction() {
- whenever(statusBarStateController.currentOrUpcomingState)
- .thenReturn(StatusBarState.KEYGUARD)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_panelOpen_setsFractionEqualToEventFraction() {
- controller.onPanelStateChanged(STATE_OPEN)
- whenever(statusBarStateController.currentOrUpcomingState)
- .thenReturn(StatusBarState.KEYGUARD)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
- }
-
- @Test
- fun onPanelExpansionChanged_inSplitShade_panelClosed_setsFractionEqualToEventFraction() {
- controller.onPanelStateChanged(STATE_CLOSED)
- whenever(statusBarStateController.currentOrUpcomingState)
- .thenReturn(StatusBarState.KEYGUARD)
- setSplitShadeEnabled(true)
-
- controller.onPanelExpansionChanged(EXPANSION_EVENT)
-
- verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
- }
-
- private fun setSplitShadeEnabled(enabled: Boolean) {
- overrideResource(R.bool.config_use_split_notification_shade, enabled)
- configurationController.notifyConfigurationChanged()
- }
-
companion object {
val EXPANSION_EVENT =
ShadeExpansionChangeEvent(
- fraction = 0.5f, expanded = true, tracking = true, dragDownPxAmount = 10f)
+ fraction = 0.5f,
+ expanded = true,
+ tracking = true,
+ dragDownPxAmount = 10f
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index eef4470..04c93cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -298,6 +298,54 @@
}
@Test
+ fun unknownPluginAttached_clockAndListUnchanged_loadRequested() {
+ val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>()
+ whenever(mockPluginLifecycle.getPackage()).thenReturn("some.other.package")
+
+ var changeCallCount = 0
+ var listChangeCallCount = 0
+ registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() { changeCallCount++ }
+ override fun onAvailableClocksChanged() { listChangeCallCount++ }
+ })
+
+ assertEquals(true, pluginListener.onPluginAttached(mockPluginLifecycle))
+ scheduler.runCurrent()
+ assertEquals(0, changeCallCount)
+ assertEquals(0, listChangeCallCount)
+ }
+
+ @Test
+ fun knownPluginAttached_clockAndListChanged_notLoaded() {
+ val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
+ whenever(mockPluginLifecycle1.getPackage()).thenReturn("com.android.systemui.falcon.one")
+ val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
+ whenever(mockPluginLifecycle2.getPackage()).thenReturn("com.android.systemui.falcon.two")
+
+ var changeCallCount = 0
+ var listChangeCallCount = 0
+ registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() { changeCallCount++ }
+ override fun onAvailableClocksChanged() { listChangeCallCount++ }
+ })
+
+ registry.applySettings(ClockSettings("DIGITAL_CLOCK_CALLIGRAPHY", null))
+ scheduler.runCurrent()
+ assertEquals(1, changeCallCount)
+ assertEquals(0, listChangeCallCount)
+
+ assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle1))
+ scheduler.runCurrent()
+ assertEquals(1, changeCallCount)
+ assertEquals(1, listChangeCallCount)
+
+ assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle2))
+ scheduler.runCurrent()
+ assertEquals(1, changeCallCount)
+ assertEquals(2, listChangeCallCount)
+ }
+
+ @Test
fun pluginAddRemove_concurrentModification() {
val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index b724175..0b1753f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -555,60 +555,6 @@
}
/**
- * Ensures a subscription is predicated on its precondition.
- */
- @Test
- public void testPrecondition() {
- mCondition1.fakeUpdateCondition(false);
- final Monitor.Callback callback =
- mock(Monitor.Callback.class);
-
- mCondition2.fakeUpdateCondition(false);
-
- // Create a nested condition
- mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(callback)
- .addPrecondition(mCondition1)
- .addCondition(mCondition2)
- .build());
-
- mExecutor.runAllReady();
-
- // Ensure the nested condition callback is not called at all.
- verify(callback, never()).onActiveChanged(anyBoolean());
- verify(callback, never()).onConditionsChanged(anyBoolean());
-
- // Update the condition to true and ensure that the nested condition is not triggered.
- mCondition2.fakeUpdateCondition(true);
- verify(callback, never()).onConditionsChanged(anyBoolean());
- mCondition2.fakeUpdateCondition(false);
-
- // Set precondition and make sure the inner condition becomes active and reports that
- // conditions aren't met
- mCondition1.fakeUpdateCondition(true);
- mExecutor.runAllReady();
-
- verify(callback).onActiveChanged(eq(true));
- verify(callback).onConditionsChanged(eq(false));
-
- Mockito.clearInvocations(callback);
-
- // Update the condition and make sure the callback is updated.
- mCondition2.fakeUpdateCondition(true);
- mExecutor.runAllReady();
-
- verify(callback).onConditionsChanged(true);
-
- Mockito.clearInvocations(callback);
- // Invalidate precondition and make sure callback is informed, but the last state is
- // not affected.
- mCondition1.fakeUpdateCondition(false);
- mExecutor.runAllReady();
-
- verify(callback).onActiveChanged(eq(false));
- verify(callback, never()).onConditionsChanged(anyBoolean());
- }
-
- /**
* Ensure preconditions are applied to every subscription added to a monitor.
*/
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index d5e904c..88d853e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -122,6 +122,7 @@
mPluginInstanceFactory.create(
mContext, mAppInfo, wrongVersionTestPluginComponentName,
TestPlugin.class, mPluginListener);
+ mPluginInstance.onCreate();
}
@Test
@@ -135,11 +136,12 @@
@Test
public void testOnDestroy() {
+ mPluginInstance.onCreate();
mPluginInstance.onDestroy();
assertEquals(1, mPluginListener.mDetachedCount);
assertEquals(1, mPluginListener.mUnloadCount);
assertNull(mPluginInstance.getPlugin());
- assertInstances(0, -1); // Destroyed but never created
+ assertInstances(0, 0); // Destroyed but never created
}
@Test
@@ -161,6 +163,16 @@
assertInstances(0, 0);
}
+ @Test
+ public void testOnAttach_SkipLoad() {
+ mPluginListener.mAttachReturn = false;
+ mPluginInstance.onCreate();
+ assertEquals(1, mPluginListener.mAttachedCount);
+ assertEquals(0, mPluginListener.mLoadCount);
+ assertEquals(null, mPluginInstance.getPlugin());
+ assertInstances(0, 0);
+ }
+
// This target class doesn't matter, it just needs to have a Requires to hit the flow where
// the mock version info is called.
@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
@@ -220,15 +232,17 @@
}
public class FakeListener implements PluginListener<TestPlugin> {
+ public boolean mAttachReturn = true;
public int mAttachedCount = 0;
public int mDetachedCount = 0;
public int mLoadCount = 0;
public int mUnloadCount = 0;
@Override
- public void onPluginAttached(PluginLifecycleManager<TestPlugin> manager) {
+ public boolean onPluginAttached(PluginLifecycleManager<TestPlugin> manager) {
mAttachedCount++;
assertEquals(PluginInstanceTest.this.mPluginInstance, manager);
+ return mAttachReturn;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 9cf5926..2d5ff24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -103,8 +103,8 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 283efe2..257cc5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -221,16 +221,35 @@
}
@Test
- fun hunExtensionCancelledWhenHunActionPressed() {
+ fun actionPressCancelsExistingLifetimeExtension() {
whenever(headsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(entry)
+
whenever(headsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
whenever(headsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
- assertTrue(notifLifetimeExtender.maybeExtendLifetime(entry, 0))
+ assertTrue(notifLifetimeExtender.maybeExtendLifetime(entry, /* reason = */ 0))
+
actionPressListener.accept(entry)
- executor.advanceClockToLast()
executor.runAllReady()
- verify(headsUpManager, times(1)).removeNotification(eq(entry.key), eq(true))
+ verify(endLifetimeExtension, times(1)).onEndLifetimeExtension(notifLifetimeExtender, entry)
+
+ collectionListener.onEntryRemoved(entry, /* reason = */ 0)
+ verify(headsUpManager, times(1)).removeNotification(eq(entry.key), any())
+ }
+
+ @Test
+ fun actionPressPreventsFutureLifetimeExtension() {
+ whenever(headsUpManager.isSticky(anyString())).thenReturn(true)
+ addHUN(entry)
+
+ actionPressListener.accept(entry)
+ verify(headsUpManager, times(1)).setUserActionMayIndirectlyRemove(entry)
+
+ whenever(headsUpManager.canRemoveImmediately(anyString())).thenReturn(true)
+ assertFalse(notifLifetimeExtender.maybeExtendLifetime(entry, 0))
+
+ collectionListener.onEntryRemoved(entry, /* reason = */ 0)
+ verify(headsUpManager, times(1)).removeNotification(eq(entry.key), any())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index ea70e9e..2fbe871 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -45,14 +46,11 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
-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.withArgCaptor
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
-import java.util.function.Consumer
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScheduler
@@ -64,8 +62,9 @@
import org.mockito.ArgumentMatchers.same
import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
-import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import java.util.function.Consumer
+import kotlin.time.Duration.Companion.seconds
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -76,6 +75,7 @@
private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock()
private val keyguardRepository = FakeKeyguardRepository()
private val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
+ private val notifPipelineFlags: NotifPipelineFlags = mock()
private val notifPipeline: NotifPipeline = mock()
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock()
private val statusBarStateController: StatusBarStateController = mock()
@@ -136,8 +136,13 @@
)
testScheduler.runCurrent()
- // THEN: We are no longer listening for shade expansions
- verify(statusBarStateController, never()).addCallback(any())
+ // WHEN: The shade is expanded
+ whenever(statusBarStateController.isExpanded).thenReturn(true)
+ statusBarStateListener.onExpandedChanged(true)
+ testScheduler.runCurrent()
+
+ // THEN: The notification is still treated as "unseen" and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
}
}
@@ -147,10 +152,6 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(false)
runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
-
// WHEN: A notification is posted
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
@@ -161,9 +162,6 @@
// WHEN: The keyguard is now showing
keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.AOD)
- )
testScheduler.runCurrent()
// THEN: The notification is recognized as "seen" and is filtered out.
@@ -171,9 +169,6 @@
// WHEN: The keyguard goes away
keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.AOD, to = KeyguardState.GONE)
- )
testScheduler.runCurrent()
// THEN: The notification is shown regardless
@@ -187,10 +182,9 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
runKeyguardCoordinatorTest {
- val fakeEntry =
- NotificationEntryBuilder()
+ val fakeEntry = NotificationEntryBuilder()
.setNotification(Notification.Builder(mContext, "id").setOngoing(true).build())
- .build()
+ .build()
collectionListener.onEntryAdded(fakeEntry)
// WHEN: The keyguard is now showing
@@ -208,13 +202,11 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
runKeyguardCoordinatorTest {
- val fakeEntry =
- NotificationEntryBuilder().build().apply {
- row =
- mock<ExpandableNotificationRow>().apply {
- whenever(isMediaRow).thenReturn(true)
- }
+ val fakeEntry = NotificationEntryBuilder().build().apply {
+ row = mock<ExpandableNotificationRow>().apply {
+ whenever(isMediaRow).thenReturn(true)
}
+ }
collectionListener.onEntryAdded(fakeEntry)
// WHEN: The keyguard is now showing
@@ -307,12 +299,14 @@
runKeyguardCoordinatorTest {
// WHEN: A new notification is posted
val fakeSummary = NotificationEntryBuilder().build()
- val fakeChild =
- NotificationEntryBuilder()
+ val fakeChild = NotificationEntryBuilder()
.setGroup(context, "group")
.setGroupSummary(context, false)
.build()
- GroupEntryBuilder().setSummary(fakeSummary).addChild(fakeChild).build()
+ GroupEntryBuilder()
+ .setSummary(fakeSummary)
+ .addChild(fakeChild)
+ .build()
collectionListener.onEntryAdded(fakeSummary)
collectionListener.onEntryAdded(fakeChild)
@@ -337,10 +331,6 @@
runKeyguardCoordinatorTest {
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
// WHEN: five seconds have passed
testScheduler.advanceTimeBy(5.seconds)
@@ -348,16 +338,10 @@
// WHEN: Keyguard is no longer showing
keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
testScheduler.runCurrent()
// WHEN: Keyguard is shown again
keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.AOD)
- )
testScheduler.runCurrent()
// THEN: The notification is now recognized as "seen" and is filtered out.
@@ -370,17 +354,11 @@
// GIVEN: Keyguard is showing, unseen notification is present
keyguardRepository.setKeyguardShowing(true)
runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
// WHEN: Keyguard is no longer showing
keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
// WHEN: Keyguard is shown again
keyguardRepository.setKeyguardShowing(true)
@@ -391,212 +369,14 @@
}
}
- @Test
- fun unseenNotificationIsNotMarkedAsSeenIfNotOnKeyguardLongEnough() {
- // GIVEN: Keyguard is showing, not dozing, unseen notification is present
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setIsDozing(false)
- runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- val firstEntry = NotificationEntryBuilder().setId(1).build()
- collectionListener.onEntryAdded(firstEntry)
- testScheduler.runCurrent()
-
- // WHEN: one second has passed
- testScheduler.advanceTimeBy(1.seconds)
- testScheduler.runCurrent()
-
- // WHEN: another unseen notification is posted
- val secondEntry = NotificationEntryBuilder().setId(2).build()
- collectionListener.onEntryAdded(secondEntry)
- testScheduler.runCurrent()
-
- // WHEN: four more seconds have passed
- testScheduler.advanceTimeBy(4.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the keyguard is no longer showing
- keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
- testScheduler.runCurrent()
-
- // WHEN: Keyguard is shown again
- keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // THEN: The first notification is considered seen and is filtered out.
- assertThat(unseenFilter.shouldFilterOut(firstEntry, 0L)).isTrue()
-
- // THEN: The second notification is still considered unseen and is not filtered out
- assertThat(unseenFilter.shouldFilterOut(secondEntry, 0L)).isFalse()
- }
- }
-
- @Test
- fun unseenNotificationOnKeyguardNotMarkedAsSeenIfRemovedAfterThreshold() {
- // GIVEN: Keyguard is showing, not dozing
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setIsDozing(false)
- runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // WHEN: a new notification is posted
- val entry = NotificationEntryBuilder().setId(1).build()
- collectionListener.onEntryAdded(entry)
- testScheduler.runCurrent()
-
- // WHEN: five more seconds have passed
- testScheduler.advanceTimeBy(5.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the notification is removed
- collectionListener.onEntryRemoved(entry, 0)
- testScheduler.runCurrent()
-
- // WHEN: the notification is re-posted
- collectionListener.onEntryAdded(entry)
- testScheduler.runCurrent()
-
- // WHEN: one more second has passed
- testScheduler.advanceTimeBy(1.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the keyguard is no longer showing
- keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
- testScheduler.runCurrent()
-
- // WHEN: Keyguard is shown again
- keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // THEN: The notification is considered unseen and is not filtered out.
- assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
- }
- }
-
- @Test
- fun unseenNotificationOnKeyguardNotMarkedAsSeenIfRemovedBeforeThreshold() {
- // GIVEN: Keyguard is showing, not dozing
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setIsDozing(false)
- runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // WHEN: a new notification is posted
- val entry = NotificationEntryBuilder().setId(1).build()
- collectionListener.onEntryAdded(entry)
- testScheduler.runCurrent()
-
- // WHEN: one second has passed
- testScheduler.advanceTimeBy(1.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the notification is removed
- collectionListener.onEntryRemoved(entry, 0)
- testScheduler.runCurrent()
-
- // WHEN: the notification is re-posted
- collectionListener.onEntryAdded(entry)
- testScheduler.runCurrent()
-
- // WHEN: one more second has passed
- testScheduler.advanceTimeBy(1.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the keyguard is no longer showing
- keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
- testScheduler.runCurrent()
-
- // WHEN: Keyguard is shown again
- keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // THEN: The notification is considered unseen and is not filtered out.
- assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
- }
- }
-
- @Test
- fun unseenNotificationOnKeyguardNotMarkedAsSeenIfUpdatedBeforeThreshold() {
- // GIVEN: Keyguard is showing, not dozing
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setIsDozing(false)
- runKeyguardCoordinatorTest {
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // WHEN: a new notification is posted
- val entry = NotificationEntryBuilder().setId(1).build()
- collectionListener.onEntryAdded(entry)
- testScheduler.runCurrent()
-
- // WHEN: one second has passed
- testScheduler.advanceTimeBy(1.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the notification is updated
- collectionListener.onEntryUpdated(entry)
- testScheduler.runCurrent()
-
- // WHEN: four more seconds have passed
- testScheduler.advanceTimeBy(4.seconds)
- testScheduler.runCurrent()
-
- // WHEN: the keyguard is no longer showing
- keyguardRepository.setKeyguardShowing(false)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
- )
- testScheduler.runCurrent()
-
- // WHEN: Keyguard is shown again
- keyguardRepository.setKeyguardShowing(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
- )
- testScheduler.runCurrent()
-
- // THEN: The notification is considered unseen and is not filtered out.
- assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
- }
- }
-
private fun runKeyguardCoordinatorTest(
testBlock: suspend KeyguardCoordinatorTestScope.() -> Unit
) {
val testDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
- val fakeSettings =
- FakeSettings().apply {
- putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
- }
+ val fakeSettings = FakeSettings().apply {
+ putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
+ }
val seenNotificationsProvider = SeenNotificationsProviderImpl()
val keyguardCoordinator =
KeyguardCoordinator(
@@ -607,6 +387,7 @@
keyguardRepository,
keyguardTransitionRepository,
mock<KeyguardCoordinatorLogger>(),
+ notifPipelineFlags,
testScope.backgroundScope,
sectionHeaderVisibilityProvider,
fakeSettings,
@@ -616,12 +397,11 @@
keyguardCoordinator.attach(notifPipeline)
testScope.runTest(dispatchTimeoutMs = 1.seconds.inWholeMilliseconds) {
KeyguardCoordinatorTestScope(
- keyguardCoordinator,
- testScope,
- seenNotificationsProvider,
- fakeSettings,
- )
- .testBlock()
+ keyguardCoordinator,
+ testScope,
+ seenNotificationsProvider,
+ fakeSettings,
+ ).testBlock()
}
}
@@ -634,9 +414,10 @@
val testScheduler: TestCoroutineScheduler
get() = scope.testScheduler
- val onStateChangeListener: Consumer<String> = withArgCaptor {
- verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
- }
+ val onStateChangeListener: Consumer<String> =
+ withArgCaptor {
+ verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
+ }
val unseenFilter: NotifFilter
get() = keyguardCoordinator.unseenNotifFilter
@@ -645,11 +426,11 @@
verify(notifPipeline).addCollectionListener(capture())
}
- val onHeadsUpChangedListener: OnHeadsUpChangedListener
- get() = withArgCaptor { verify(headsUpManager).addListener(capture()) }
+ val onHeadsUpChangedListener: OnHeadsUpChangedListener get() =
+ withArgCaptor { verify(headsUpManager).addListener(capture()) }
- val statusBarStateListener: StatusBarStateController.StateListener
- get() = withArgCaptor { verify(statusBarStateController).addCallback(capture()) }
+ val statusBarStateListener: StatusBarStateController.StateListener get() =
+ withArgCaptor { verify(statusBarStateController).addCallback(capture()) }
var showOnlyUnseenNotifsOnKeyguardSetting: Boolean
get() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 05b70eb..8c27a7dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -8,7 +8,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.StatusBarIconView
@@ -311,9 +310,8 @@
}
@Test
- fun updateState_flagTrue_largeScreen_expansionChanging_shelfAlphaUpdated_largeScreenValue() {
+ fun updateState_largeScreen_expansionChanging_shelfAlphaUpdated_largeScreenValue() {
val expansionFraction = 0.6f
- whenever(flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)).thenReturn(true)
whenever(ambientState.isSmallScreen).thenReturn(false)
whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
.thenReturn(0.123f)
@@ -325,20 +323,6 @@
}
@Test
- fun updateState_flagFalse_largeScreen_expansionChanging_shelfAlphaUpdated_standardValue() {
- val expansionFraction = 0.6f
- whenever(flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)).thenReturn(false)
- whenever(ambientState.isSmallScreen).thenReturn(false)
- whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
- .thenReturn(0.123f)
-
- updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = expansionFraction,
- expectedAlpha = ShadeInterpolation.getContentAlpha(expansionFraction)
- )
- }
-
- @Test
fun updateState_expansionChangingWhileBouncerInTransit_shelfAlphaUpdated() {
whenever(ambientState.isBouncerInTransit).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 0e966dc..18cf876 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -44,10 +44,12 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
@@ -122,6 +124,7 @@
@Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private KeyguardInteractor mKeyguardInteractor;
+ @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
@Mock private DumpManager mDumpManager;
@@ -145,7 +148,7 @@
@Mock private StackStateLogger mStackLogger;
@Mock private NotificationStackScrollLogger mLogger;
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
- @Mock private FeatureFlags mFeatureFlags;
+ private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
@Mock private SecureSettings mSecureSettings;
@Mock private NotificationIconAreaController mIconAreaController;
@@ -163,6 +166,8 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, false);
+
when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
}
@@ -262,28 +267,84 @@
}
@Test
- public void testUpdateEmptyShadeView_bouncerShowing_hideEmptyView() {
+ public void testUpdateEmptyShadeView_bouncerShowing_flagOff_hideEmptyView() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
initController(/* viewIsAttached= */ true);
- when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+ // WHEN the flag is off and *only* CentralSurfaces has bouncer as showing
+ mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, false);
+ mController.setBouncerShowingFromCentralSurfaces(true);
+ when(mPrimaryBouncerInteractor.isBouncerShowing()).thenReturn(false);
+
setupShowEmptyShadeViewState(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
+
+ // THEN the CentralSurfaces value is used. Since the bouncer is showing, we hide the empty
+ // view.
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ false,
/* areNotificationsHiddenInShade= */ false);
}
@Test
- public void testUpdateEmptyShadeView_bouncerNotShowing_showEmptyView() {
+ public void testUpdateEmptyShadeView_bouncerShowing_flagOn_hideEmptyView() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
initController(/* viewIsAttached= */ true);
- when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
+ // WHEN the flag is on and *only* PrimaryBouncerInteractor has bouncer as showing
+ mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, true);
+ when(mPrimaryBouncerInteractor.isBouncerShowing()).thenReturn(true);
+ mController.setBouncerShowingFromCentralSurfaces(false);
+
setupShowEmptyShadeViewState(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
+
+ // THEN the PrimaryBouncerInteractor value is used. Since the bouncer is showing, we
+ // hide the empty view.
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ /* visible= */ false,
+ /* areNotificationsHiddenInShade= */ false);
+ }
+
+ @Test
+ public void testUpdateEmptyShadeView_bouncerNotShowing_flagOff_showEmptyView() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+ initController(/* viewIsAttached= */ true);
+
+ // WHEN the flag is off and *only* CentralSurfaces has bouncer as not showing
+ mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, false);
+ mController.setBouncerShowingFromCentralSurfaces(false);
+ when(mPrimaryBouncerInteractor.isBouncerShowing()).thenReturn(true);
+
+ setupShowEmptyShadeViewState(true);
+ reset(mNotificationStackScrollLayout);
+ mController.updateShowEmptyShadeView();
+
+ // THEN the CentralSurfaces value is used. Since the bouncer isn't showing, we can show the
+ // empty view.
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+ /* visible= */ true,
+ /* areNotificationsHiddenInShade= */ false);
+ }
+
+ @Test
+ public void testUpdateEmptyShadeView_bouncerNotShowing_flagOn_showEmptyView() {
+ when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+ initController(/* viewIsAttached= */ true);
+
+ // WHEN the flag is on and *only* PrimaryBouncerInteractor has bouncer as not showing
+ mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, true);
+ when(mPrimaryBouncerInteractor.isBouncerShowing()).thenReturn(false);
+ mController.setBouncerShowingFromCentralSurfaces(true);
+
+ setupShowEmptyShadeViewState(true);
+ reset(mNotificationStackScrollLayout);
+ mController.updateShowEmptyShadeView();
+
+ // THEN the PrimaryBouncerInteractor value is used. Since the bouncer isn't showing, we
+ // can show the empty view.
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
/* areNotificationsHiddenInShade= */ false);
@@ -548,6 +609,7 @@
mKeyguardMediaController,
mKeyguardBypassController,
mKeyguardInteractor,
+ mPrimaryBouncerInteractor,
mZenModeController,
mNotificationLockscreenUserManager,
Optional.<NotificationListViewModel>empty(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 7632d01..df65c09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -29,6 +30,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.animation.Animator;
@@ -670,6 +672,28 @@
}
@Test
+ public void testForceResetSwipeStateDoesNothingIfTranslationIsZero() {
+ doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
+ doReturn(0f).when(mNotificationRow).getTranslationX();
+
+ mSwipeHelper.forceResetSwipeState(mNotificationRow);
+
+ verify(mNotificationRow).getTranslationX();
+ verifyNoMoreInteractions(mNotificationRow);
+ }
+
+ @Test
+ public void testForceResetSwipeStateResetsTranslationAndAlpha() {
+ doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
+ doReturn(10f).when(mNotificationRow).getTranslationX();
+
+ mSwipeHelper.forceResetSwipeState(mNotificationRow);
+
+ verify(mNotificationRow).setTranslation(eq(0f));
+ verify(mNotificationRow).setContentAlpha(eq(1f));
+ }
+
+ @Test
public void testContentAlphaRemainsUnchangedWhenFeatureFlagIsDisabled() {
// Returning true prevents alpha fade. In an unmocked scenario the callback is instantiated
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index e12d179..d107a0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -9,7 +9,6 @@
import com.android.systemui.animation.ShadeInterpolation.getContentAlpha
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.EmptyShadeView
import com.android.systemui.statusbar.NotificationShelf
@@ -35,7 +34,6 @@
@SmallTest
class StackScrollAlgorithmTest : SysuiTestCase() {
-
@JvmField @Rule
var expect: Expect = Expect.create()
@@ -82,26 +80,58 @@
fun resetViewStates_defaultHun_yTranslationIsInset() {
whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true)
-
- stackScrollAlgorithm.resetViewStates(ambientState, 0)
-
- assertThat(notificationRow.viewState.yTranslation)
- .isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
+ resetViewStates_hunYTranslationIsInset()
}
@Test
- fun resetViewStates_stackMargin_changesHunYTranslation() {
+ fun resetViewStates_defaultHunWithStackMargin_changesHunYTranslation() {
whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true)
- val minHeadsUpTranslation = context.resources
- .getDimensionPixelSize(R.dimen.notification_side_paddings)
+ resetViewStates_stackMargin_changesHunYTranslation()
+ }
- // split shade case with top margin introduced by shade's status bar
- ambientState.stackTopMargin = 100
- stackScrollAlgorithm.resetViewStates(ambientState, 0)
+ @Test
+ fun resetViewStates_hunAnimatingAway_yTranslationIsInset() {
+ whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
+ resetViewStates_hunYTranslationIsInset()
+ }
- // top margin presence should decrease heads up translation up to minHeadsUpTranslation
- assertThat(notificationRow.viewState.yTranslation).isEqualTo(minHeadsUpTranslation)
+ @Test
+ fun resetViewStates_hunAnimatingAway_StackMarginChangesHunYTranslation() {
+ whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
+ resetViewStates_stackMargin_changesHunYTranslation()
+ }
+
+ @Test
+ fun resetViewStates_hunAnimatingAway_bottomNotClipped() {
+ whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ assertThat(notificationRow.viewState.clipBottomAmount).isEqualTo(0)
+ }
+
+ @Test
+ fun resetViewStates_hunsOverlapping_bottomHunClipped() {
+ val topHun = mockExpandableNotificationRow()
+ val bottomHun = mockExpandableNotificationRow()
+ whenever(topHun.isHeadsUp).thenReturn(true)
+ whenever(topHun.isPinned).thenReturn(true)
+ whenever(bottomHun.isHeadsUp).thenReturn(true)
+ whenever(bottomHun.isPinned).thenReturn(true)
+
+ resetViewStates_hunsOverlapping_bottomHunClipped(topHun, bottomHun)
+ }
+
+ @Test
+ fun resetViewStates_hunsOverlappingAndBottomHunAnimatingAway_bottomHunClipped() {
+ val topHun = mockExpandableNotificationRow()
+ val bottomHun = mockExpandableNotificationRow()
+ whenever(topHun.isHeadsUp).thenReturn(true)
+ whenever(topHun.isPinned).thenReturn(true)
+ whenever(bottomHun.isHeadsUpAnimatingAway).thenReturn(true)
+
+ resetViewStates_hunsOverlapping_bottomHunClipped(topHun, bottomHun)
}
@Test
@@ -160,12 +190,10 @@
}
@Test
- fun resetViewStates_flagTrue_largeScreen_expansionChanging_alphaUpdated_largeScreenValue() {
+ fun resetViewStates_largeScreen_expansionChanging_alphaUpdated_largeScreenValue() {
val expansionFraction = 0.6f
val surfaceAlpha = 123f
ambientState.isSmallScreen = false
- whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(true)
whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false)
whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
.thenReturn(surfaceAlpha)
@@ -177,23 +205,6 @@
}
@Test
- fun resetViewStates_flagFalse_largeScreen_expansionChanging_alphaUpdated_standardValue() {
- val expansionFraction = 0.6f
- val surfaceAlpha = 123f
- ambientState.isSmallScreen = false
- whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(false)
- whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false)
- whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
- .thenReturn(surfaceAlpha)
-
- resetViewStates_expansionChanging_notificationAlphaUpdated(
- expansionFraction = expansionFraction,
- expectedAlpha = getContentAlpha(expansionFraction),
- )
- }
-
- @Test
fun expansionChanging_largeScreen_bouncerInTransit_alphaUpdated_bouncerValues() {
ambientState.isSmallScreen = false
whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(true)
@@ -855,6 +866,57 @@
ambientState.stackHeight = ambientState.stackEndHeight * fraction
}
+ private fun resetViewStates_hunYTranslationIsInset() {
+ stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+ assertThat(notificationRow.viewState.yTranslation)
+ .isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
+ }
+
+ private fun resetViewStates_stackMargin_changesHunYTranslation() {
+ val stackTopMargin = 50
+ val headsUpTranslationY = stackScrollAlgorithm.mHeadsUpInset - stackTopMargin
+
+ // we need the shelf to mock the real-life behaviour of StackScrollAlgorithm#updateChild
+ ambientState.shelf = notificationShelf
+
+ // split shade case with top margin introduced by shade's status bar
+ ambientState.stackTopMargin = stackTopMargin
+ stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+ // heads up translation should be decreased by the top margin
+ assertThat(notificationRow.viewState.yTranslation).isEqualTo(headsUpTranslationY)
+ }
+
+ private fun resetViewStates_hunsOverlapping_bottomHunClipped(
+ topHun: ExpandableNotificationRow,
+ bottomHun: ExpandableNotificationRow
+ ) {
+ val topHunHeight = mContext.resources.getDimensionPixelSize(
+ R.dimen.notification_content_min_height)
+ val bottomHunHeight = mContext.resources.getDimensionPixelSize(
+ R.dimen.notification_max_heads_up_height)
+ whenever(topHun.intrinsicHeight).thenReturn(topHunHeight)
+ whenever(bottomHun.intrinsicHeight).thenReturn(bottomHunHeight)
+
+ // we need the shelf to mock the real-life behaviour of StackScrollAlgorithm#updateChild
+ ambientState.shelf = notificationShelf
+
+ // add two overlapping HUNs
+ hostView.removeAllViews()
+ hostView.addView(topHun)
+ hostView.addView(bottomHun)
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ // the height shouldn't change
+ assertThat(topHun.viewState.height).isEqualTo(topHunHeight)
+ assertThat(bottomHun.viewState.height).isEqualTo(bottomHunHeight)
+ // the HUN at the bottom should be clipped
+ assertThat(topHun.viewState.clipBottomAmount).isEqualTo(0)
+ assertThat(bottomHun.viewState.clipBottomAmount).isEqualTo(bottomHunHeight - topHunHeight)
+ }
+
private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
expansionFraction: Float,
expectedAlpha: Float,
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 4fb5b07..21dae03 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
@@ -113,7 +113,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
@@ -145,6 +145,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
@@ -273,6 +274,7 @@
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
+ @Mock private NotificationShelfController mNotificationShelfController;
@Mock private DozeParameters mDozeParameters;
@Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
@Mock private LockscreenWallpaper mLockscreenWallpaper;
@@ -499,6 +501,7 @@
() -> mAssistManager,
configurationController,
mNotificationShadeWindowController,
+ mNotificationShelfController,
mDozeParameters,
mScrimController,
mLockscreenWallpaperLazy,
@@ -580,6 +583,7 @@
mCentralSurfaces.mPresenter = mNotificationPresenter;
mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;
mCentralSurfaces.mBarService = mBarService;
+ mCentralSurfaces.mStackScrollerController = mStackScrollerController;
mCentralSurfaces.mStackScroller = mStackScroller;
mCentralSurfaces.mGestureWakeLock = mPowerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "sysui:GestureWakeLock");
@@ -1059,7 +1063,7 @@
// GIVEN device occluded and panel is NOT expanded
mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
when(mKeyguardStateController.isOccluded()).thenReturn(true);
- mCentralSurfaces.mPanelExpanded = false;
+ when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(false);
mCentralSurfaces.updateScrimController();
@@ -1073,7 +1077,7 @@
// GIVEN device occluded and qs IS expanded
mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
when(mKeyguardStateController.isOccluded()).thenReturn(true);
- mCentralSurfaces.mPanelExpanded = true;
+ when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
mCentralSurfaces.updateScrimController();
@@ -1142,32 +1146,6 @@
}
@Test
- public void collapseShade_callsanimateCollapseShade_whenExpanded() {
- // GIVEN the shade is expanded
- mCentralSurfaces.onShadeExpansionFullyChanged(true);
- mCentralSurfaces.setBarStateForTest(SHADE);
-
- // WHEN collapseShade is called
- mCentralSurfaces.collapseShade();
-
- // VERIFY that animateCollapseShade is called
- verify(mShadeController).animateCollapseShade();
- }
-
- @Test
- public void collapseShade_doesNotCallanimateCollapseShade_whenCollapsed() {
- // GIVEN the shade is collapsed
- mCentralSurfaces.onShadeExpansionFullyChanged(false);
- mCentralSurfaces.setBarStateForTest(SHADE);
-
- // WHEN collapseShade is called
- mCentralSurfaces.collapseShade();
-
- // VERIFY that animateCollapseShade is NOT called
- verify(mShadeController, never()).animateCollapseShade();
- }
-
- @Test
public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() {
setFoldedStates(FOLD_STATE_FOLDED);
setGoToSleepStates(FOLD_STATE_FOLDED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 7e69efa..5d2b59b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -67,6 +67,8 @@
private float mQsExpansion;
private int mCutoutTopInset = 0;
private boolean mIsSplitShade = false;
+ private boolean mBypassEnabled = false;
+ private int mUnlockedStackScrollerPadding = 0;
private float mUdfpsTop = -1;
private float mClockBottom = SCREEN_HEIGHT / 2;
private boolean mClockTopAligned;
@@ -339,15 +341,52 @@
}
@Test
- public void notifMinPaddingAlignedWithClockInSplitShadeMode() {
+ public void notifPadding_splitShade() {
givenLockScreen();
mIsSplitShade = true;
mKeyguardStatusHeight = 200;
// WHEN the position algorithm is run
positionClock();
// THEN the padding DOESN'T adjust for keyguard status height.
- assertThat(mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding())
- .isEqualTo(mKeyguardStatusBarHeaderHeight);
+ assertThat(mClockPositionAlgorithm.getLockscreenNotifPadding(/* nsslTop= */ 10))
+ .isEqualTo(mKeyguardStatusBarHeaderHeight - 10);
+ }
+
+ @Test
+ public void notifPadding_portraitShade_bypassOff() {
+ givenLockScreen();
+ mIsSplitShade = false;
+ mBypassEnabled = false;
+
+ // mMinTopMargin = 100 = 80 + max(20, 0)
+ mKeyguardStatusBarHeaderHeight = 80;
+ mUserSwitchHeight = 20;
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
+ .thenReturn(0);
+
+ mKeyguardStatusHeight = 200;
+
+ // WHEN the position algorithm is run
+ positionClock();
+
+ // THEN padding = 300 = mMinTopMargin(100) + mKeyguardStatusHeight(200)
+ assertThat(mClockPositionAlgorithm.getLockscreenNotifPadding(/* nsslTop= */ 50))
+ .isEqualTo(300);
+ }
+
+ @Test
+ public void notifPadding_portraitShade_bypassOn() {
+ givenLockScreen();
+ mIsSplitShade = false;
+ mBypassEnabled = true;
+ mUnlockedStackScrollerPadding = 200;
+
+ // WHEN the position algorithm is run
+ positionClock();
+
+ // THEN padding = 150 = mUnlockedStackScrollerPadding(200) - nsslTop(50)
+ assertThat(mClockPositionAlgorithm.getLockscreenNotifPadding(/* nsslTop= */ 50))
+ .isEqualTo(150);
}
@Test
@@ -589,8 +628,8 @@
0 /* userSwitchPreferredY */,
mDark,
ZERO_DRAG,
- false /* bypassEnabled */,
- 0 /* unlockedStackScrollerPadding */,
+ mBypassEnabled,
+ mUnlockedStackScrollerPadding,
mQsExpansion,
mCutoutTopInset,
mIsSplitShade,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index a9ed175..ab80158 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -61,10 +61,9 @@
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -697,9 +696,7 @@
}
@Test
- public void transitionToUnlocked_nonClippedQs_flagTrue_followsLargeScreensInterpolator() {
- when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(true);
+ public void transitionToUnlocked_nonClippedQs_followsLargeScreensInterpolator() {
mScrimController.setClipsQsScrim(false);
mScrimController.setRawPanelExpansionFraction(0f);
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -737,48 +734,6 @@
mScrimBehind, OPAQUE));
}
-
- @Test
- public void transitionToUnlocked_nonClippedQs_flagFalse() {
- when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
- .thenReturn(false);
- mScrimController.setClipsQsScrim(false);
- mScrimController.setRawPanelExpansionFraction(0f);
- mScrimController.transitionTo(ScrimState.UNLOCKED);
- finishAnimationsImmediately();
- assertScrimAlpha(Map.of(
- mScrimInFront, TRANSPARENT,
- mNotificationsScrim, TRANSPARENT,
- mScrimBehind, TRANSPARENT));
-
- assertScrimTinted(Map.of(
- mNotificationsScrim, false,
- mScrimInFront, false,
- mScrimBehind, true
- ));
-
- // Back scrim should be visible after start dragging
- mScrimController.setRawPanelExpansionFraction(0.29f);
- assertScrimAlpha(Map.of(
- mScrimInFront, TRANSPARENT,
- mNotificationsScrim, TRANSPARENT,
- mScrimBehind, SEMI_TRANSPARENT));
-
- // Back scrim should be opaque at 30%
- mScrimController.setRawPanelExpansionFraction(0.3f);
- assertScrimAlpha(Map.of(
- mScrimInFront, TRANSPARENT,
- mNotificationsScrim, TRANSPARENT,
- mScrimBehind, OPAQUE));
-
- // Then, notification scrim should fade in
- mScrimController.setRawPanelExpansionFraction(0.31f);
- assertScrimAlpha(Map.of(
- mScrimInFront, TRANSPARENT,
- mNotificationsScrim, SEMI_TRANSPARENT,
- mScrimBehind, OPAQUE));
- }
-
@Test
public void scrimStateCallback() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
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 8ad522a..914e295 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
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
+import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -64,12 +64,12 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.data.BouncerView;
-import com.android.systemui.keyguard.data.BouncerViewDelegate;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.ui.BouncerView;
+import com.android.systemui.bouncer.ui.BouncerViewDelegate;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index c8c24a7..6301fa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -47,7 +47,8 @@
testScope = TestScope(UnconfinedTestDispatcher())
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+ val interactor =
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 487d26d..a797e03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -20,7 +20,6 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -346,4 +345,17 @@
assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
mUiEventLoggerFake.eventId(0));
}
+
+ @Test
+ public void testSetUserActionMayIndirectlyRemove() {
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ mHeadsUpManager.showNotification(notifEntry);
+ assertFalse(mHeadsUpManager.canRemoveImmediately(notifEntry.getKey()));
+
+ mHeadsUpManager.setUserActionMayIndirectlyRemove(notifEntry);
+ assertTrue(mHeadsUpManager.canRemoveImmediately(notifEntry.getKey()));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
new file mode 100644
index 0000000..2013bb0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.util.kotlin
+
+import android.content.ComponentName
+import android.content.pm.ComponentInfo
+import android.content.pm.PackageManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class PackageManagerExtComponentEnabledTest(private val testCase: TestCase) :
+ SysuiTestCase() {
+
+ @Mock private lateinit var packageManager: PackageManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testComponentActuallyEnabled() {
+ whenever(packageManager.getComponentEnabledSetting(TEST_COMPONENT))
+ .thenReturn(testCase.componentEnabledSetting)
+ val componentInfo =
+ mock<ComponentInfo>() {
+ whenever(isEnabled).thenReturn(testCase.componentIsEnabled)
+ whenever(componentName).thenReturn(TEST_COMPONENT)
+ }
+
+ assertThat(packageManager.isComponentActuallyEnabled(componentInfo))
+ .isEqualTo(testCase.expected)
+ }
+
+ internal data class TestCase(
+ @PackageManager.EnabledState val componentEnabledSetting: Int,
+ val componentIsEnabled: Boolean,
+ val expected: Boolean,
+ ) {
+ override fun toString(): String {
+ return "WHEN(" +
+ "componentIsEnabled = $componentIsEnabled, " +
+ "componentEnabledSetting = ${enabledStateToString()}) then " +
+ "EXPECTED = $expected"
+ }
+
+ private fun enabledStateToString() =
+ when (componentEnabledSetting) {
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> "STATE_DEFAULT"
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> "STATE_DISABLED"
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED -> {
+ "STATE_DISABLED_UNTIL_USED"
+ }
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> "STATE_DISABLED_USER"
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> "STATE_ENABLED"
+ else -> "INVALID STATE"
+ }
+ }
+
+ companion object {
+ @Parameters(name = "{0}") @JvmStatic fun data(): Collection<TestCase> = testData
+
+ private val testDataComponentIsEnabled =
+ listOf(
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ componentIsEnabled = true,
+ expected = true,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER,
+ componentIsEnabled = true,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ componentIsEnabled = true,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting =
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ componentIsEnabled = true,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ componentIsEnabled = true,
+ expected = true,
+ ),
+ )
+
+ private val testDataComponentIsDisabled =
+ listOf(
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ componentIsEnabled = false,
+ expected = true,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER,
+ componentIsEnabled = false,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ componentIsEnabled = false,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting =
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ componentIsEnabled = false,
+ expected = false,
+ ),
+ TestCase(
+ componentEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ componentIsEnabled = false,
+ expected = false,
+ ),
+ )
+
+ private val testData = testDataComponentIsDisabled + testDataComponentIsEnabled
+
+ private val TEST_COMPONENT = ComponentName("pkg", "cls")
+ }
+}
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 8f725be..ef3a332 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -16,13 +16,19 @@
package com.android.systemui.volume;
+import static android.media.AudioManager.RINGER_MODE_NORMAL;
+import static android.media.AudioManager.RINGER_MODE_SILENT;
+import static android.media.AudioManager.RINGER_MODE_VIBRATE;
+
import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -293,7 +299,7 @@
@Test
public void testSelectVibrateFromDrawer() {
final State initialUnsetState = new State();
- initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+ initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
mDialog.onStateChangedH(initialUnsetState);
mActiveRinger.performClick();
@@ -307,7 +313,7 @@
@Test
public void testSelectMuteFromDrawer() {
final State initialUnsetState = new State();
- initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+ initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
mDialog.onStateChangedH(initialUnsetState);
mActiveRinger.performClick();
@@ -329,7 +335,7 @@
// Make sure we've actually changed the ringer mode.
verify(mVolumeDialogController, times(1)).setRingerMode(
- AudioManager.RINGER_MODE_NORMAL, false);
+ RINGER_MODE_NORMAL, false);
}
/**
@@ -511,6 +517,87 @@
}
}
+ private enum RingerDrawerState {INIT, OPEN, CLOSE}
+
+ @Test
+ public void ringerModeNormal_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.INIT);
+ }
+
+ @Test
+ public void ringerModeSilent_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.INIT);
+ }
+
+ @Test
+ public void ringerModeVibrate_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.INIT);
+ }
+
+ @Test
+ public void ringerModeNormal_openDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.OPEN);
+ }
+
+ @Test
+ public void ringerModeSilent_openDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.OPEN);
+ }
+
+ @Test
+ public void ringerModeVibrate_openDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.OPEN);
+ }
+
+ @Test
+ public void ringerModeNormal_closeDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.CLOSE);
+ }
+
+ @Test
+ public void ringerModeSilent_closeDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.CLOSE);
+ }
+
+ @Test
+ public void ringerModeVibrate_closeDrawer_ringerContainerDescribesItsState() {
+ assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.CLOSE);
+ }
+
+ /**
+ * The content description should include ringer state, and the correct one.
+ */
+ private void assertRingerContainerDescribesItsState(int ringerMode,
+ RingerDrawerState drawerState) {
+ State state = createShellState();
+ state.ringerModeInternal = ringerMode;
+ mDialog.onStateChangedH(state);
+
+ mDialog.show(SHOW_REASON_UNKNOWN);
+
+ if (drawerState != RingerDrawerState.INIT) {
+ // in both cases we first open the drawer
+ mDialog.toggleRingerDrawer(true);
+
+ if (drawerState == RingerDrawerState.CLOSE) {
+ mDialog.toggleRingerDrawer(false);
+ }
+ }
+
+ String ringerContainerDescription = mDialog.getSelectedRingerContainerDescription();
+ assumeNotNull(ringerContainerDescription);
+
+ String ringerDescription = mContext.getString(
+ mDialog.getStringDescriptionResourceForRingerMode(ringerMode));
+
+ if (drawerState == RingerDrawerState.OPEN) {
+ assertEquals(ringerDescription, ringerContainerDescription);
+ } else {
+ assertNotSame(ringerDescription, ringerContainerDescription);
+ assertTrue(ringerContainerDescription.startsWith(ringerDescription));
+ }
+ }
+
@After
public void teardown() {
if (mDialog != null) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
index 9179efc..e470406 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -57,8 +57,7 @@
@Before
public void sysuiSetup() throws ExecutionException, InterruptedException {
- SystemUIInitializer initializer =
- SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ SystemUIInitializer initializer = new SystemUIInitializerImpl(mContext);
initializer.init(true);
mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
Dependency.setInstance(mDependency);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 8bbd58d..de177168 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -90,8 +90,7 @@
if (isRobolectricTest()) {
mContext = mContext.createDefaultDisplayContext();
}
- SystemUIInitializer initializer =
- SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ SystemUIInitializer initializer = new SystemUIInitializerImpl(mContext);
initializer.init(true);
mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
Dependency.setInstance(mDependency);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBouncerMessageRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
similarity index 93%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBouncerMessageRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
index b03b4ba..d9b926d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBouncerMessageRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.data.repository
+package com.android.systemui.bouncer.data.repository
-import com.android.systemui.keyguard.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.keyguard.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
similarity index 81%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index 8a6d2aa..10529e6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -1,24 +1,7 @@
-/*
- * 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.bouncer.data.repository
-package com.android.systemui.keyguard.data.repository
-
-import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
-import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
+import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -36,7 +19,7 @@
_primaryBouncerDisappearAnimation.asStateFlow()
private val _primaryBouncerScrimmed = MutableStateFlow(false)
override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()
- private val _panelExpansionAmount = MutableStateFlow(EXPANSION_HIDDEN)
+ private val _panelExpansionAmount = MutableStateFlow(KeyguardBouncerConstants.EXPANSION_HIDDEN)
override val panelExpansionAmount = _panelExpansionAmount.asStateFlow()
private val _keyguardPosition = MutableStateFlow(0f)
override val keyguardPosition = _keyguardPosition.asStateFlow()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index c7ca7ce..f13c98d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -17,11 +17,11 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
/**
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
index 15465f4..3334f3e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.power.data.repository
+import android.os.PowerManager
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -28,7 +29,15 @@
private val _isInteractive = MutableStateFlow(initialInteractive)
override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow()
+ var lastWakeWhy: String? = null
+ var lastWakeReason: Int? = null
+
fun setInteractive(value: Boolean) {
_isInteractive.value = value
}
+
+ override fun wakeUp(why: String, @PowerManager.WakeReason wakeReason: Int) {
+ lastWakeWhy = why
+ lastWakeReason = wakeReason
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeInstalledTilesComponentRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeInstalledTilesComponentRepository.kt
new file mode 100644
index 0000000..ff6b7d0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeInstalledTilesComponentRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.qs.pipeline.data.repository
+
+import android.content.ComponentName
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeInstalledTilesComponentRepository : InstalledTilesComponentRepository {
+
+ private val installedComponentsPerUser =
+ mutableMapOf<Int, MutableStateFlow<Set<ComponentName>>>()
+
+ override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> {
+ return getFlow(userId).asStateFlow()
+ }
+
+ fun setInstalledPackagesForUser(userId: Int, components: Set<ComponentName>) {
+ getFlow(userId).value = components
+ }
+
+ private fun getFlow(userId: Int): MutableStateFlow<Set<ComponentName>> =
+ installedComponentsPerUser.getOrPut(userId) { MutableStateFlow(emptySet()) }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index be3d54a..1b7542b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -20,7 +20,7 @@
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
-import com.android.systemui.bouncer.data.repo.BouncerRepository
+import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1a57bc1..ec4203e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -63,6 +63,7 @@
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.LocalLog;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -334,7 +335,8 @@
// of time.
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.onSwitchInputMethod();
}
@@ -366,11 +368,12 @@
boolean isTemporary) {
mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary);
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service == null) {
// If we cannot get the service from the services cache, it will call
// updateRemoteAugmentedAutofillService() finally. Skip call this update again.
- getServiceForUserLocked(userId);
+ getServiceForUserWithLocalBinderIdentityLocked(userId);
} else {
service.updateRemoteAugmentedAutofillService();
}
@@ -380,17 +383,46 @@
private void onFieldClassificationServiceNameChanged(
@UserIdInt int userId, @Nullable String serviceName, boolean isTemporary) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service == null) {
// If we cannot get the service from the services cache, it will call
// updateRemoteFieldClassificationService() finally. Skip call this update again.
- getServiceForUserLocked(userId);
+ getServiceForUserWithLocalBinderIdentityLocked(userId);
} else {
service.updateRemoteFieldClassificationService();
}
}
}
+ @GuardedBy("mLock")
+ @Nullable
+ private AutofillManagerServiceImpl getServiceForUserWithLocalBinderIdentityLocked(int userId) {
+ final long token = Binder.clearCallingIdentity();
+ AutofillManagerServiceImpl managerService = null;
+ try {
+ managerService = getServiceForUserLocked(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return managerService;
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private AutofillManagerServiceImpl peekServiceForUserWithLocalBinderIdentityLocked(int userId) {
+ final long token = Binder.clearCallingIdentity();
+ AutofillManagerServiceImpl managerService = null;
+ try {
+ managerService = peekServiceForUserLocked(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return managerService;
+ }
+
@Override // from AbstractMasterSystemService
protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
@@ -1038,7 +1070,8 @@
mUi.hideAll(null);
synchronized (mLock) {
final AutofillManagerServiceImpl service =
- getServiceForUserLocked(UserHandle.getCallingUserId());
+ getServiceForUserWithLocalBinderIdentityLocked(
+ UserHandle.getCallingUserId());
service.onBackKeyPressed();
}
}
@@ -1537,20 +1570,27 @@
public void addClient(IAutoFillManagerClient client, ComponentName componentName,
int userId, IResultReceiver receiver) {
int flags = 0;
- synchronized (mLock) {
- final int enabledFlags = getServiceForUserLocked(userId).addClientLocked(client,
- componentName);
- if (enabledFlags != 0) {
- flags |= enabledFlags;
+ try {
+ synchronized (mLock) {
+ final int enabledFlags =
+ getServiceForUserWithLocalBinderIdentityLocked(userId)
+ .addClientLocked(client, componentName);
+ if (enabledFlags != 0) {
+ flags |= enabledFlags;
+ }
+ if (sDebug) {
+ flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+ }
+ if (sVerbose) {
+ flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
+ }
}
- if (sDebug) {
- flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
- }
- if (sVerbose) {
- flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
- }
+ } catch (Exception ex) {
+ // Don't do anything, send back default flags
+ Log.wtf(TAG, "addClient(): failed " + ex.toString());
+ } finally {
+ send(receiver, flags);
}
- send(receiver, flags);
}
@Override
@@ -1569,7 +1609,8 @@
public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ getServiceForUserWithLocalBinderIdentityLocked(userId);
service.setAuthenticationResultLocked(data, sessionId, authenticationId,
getCallingUid());
}
@@ -1578,7 +1619,8 @@
@Override
public void setHasCallback(int sessionId, int userId, boolean hasIt) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ getServiceForUserWithLocalBinderIdentityLocked(userId);
service.setHasCallback(sessionId, getCallingUid(), hasIt);
}
}
@@ -1608,7 +1650,8 @@
final int taskId = mAm.getTaskIdForActivity(activityToken, false);
final long result;
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ getServiceForUserWithLocalBinderIdentityLocked(userId);
result = service.startSessionLocked(activityToken, taskId, getCallingUid(),
clientCallback, autofillId, bounds, value, hasCallback, clientActivity,
compatMode, mAllowInstantService, flags);
@@ -1624,51 +1667,72 @@
@Override
public void getFillEventHistory(@NonNull IResultReceiver receiver) throws RemoteException {
+ FillEventHistory fillEventHistory = null;
final int userId = UserHandle.getCallingUserId();
- FillEventHistory fillEventHistory = null;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- fillEventHistory = service.getFillEventHistory(getCallingUid());
- } else if (sVerbose) {
- Slog.v(TAG, "getFillEventHistory(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ fillEventHistory = service.getFillEventHistory(getCallingUid());
+ } else if (sVerbose) {
+ Slog.v(TAG, "getFillEventHistory(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ // Do not raise the exception, just send back the null response
+ Log.wtf(TAG, "getFillEventHistory(): failed " + ex.toString());
+ } finally {
+ send(receiver, fillEventHistory);
}
- send(receiver, fillEventHistory);
}
@Override
public void getUserData(@NonNull IResultReceiver receiver) throws RemoteException {
+ UserData userData = null;
final int userId = UserHandle.getCallingUserId();
- UserData userData = null;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- userData = service.getUserData(getCallingUid());
- } else if (sVerbose) {
- Slog.v(TAG, "getUserData(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ userData = service.getUserData(getCallingUid());
+ } else if (sVerbose) {
+ Slog.v(TAG, "getUserData(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ // Do not raise the exception, just send back the null response
+ Log.wtf(TAG, "getUserData(): failed " + ex.toString());
+ } finally {
+ send(receiver, userData);
}
- send(receiver, userData);
}
@Override
public void getUserDataId(@NonNull IResultReceiver receiver) throws RemoteException {
- final int userId = UserHandle.getCallingUserId();
UserData userData = null;
+ final int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- userData = service.getUserData(getCallingUid());
- } else if (sVerbose) {
- Slog.v(TAG, "getUserDataId(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ userData = service.getUserData(getCallingUid());
+ } else if (sVerbose) {
+ Slog.v(TAG, "getUserDataId(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ // Do not raise the exception, just send back the null response
+ Log.wtf(TAG, "getUserDataId(): failed " + ex.toString());
+ } finally {
+ final String userDataId = userData == null ? null : userData.getId();
+ send(receiver, userDataId);
}
- final String userDataId = userData == null ? null : userData.getId();
- send(receiver, userDataId);
}
@Override
@@ -1676,7 +1740,8 @@
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.setUserData(getCallingUid(), userData);
} else if (sVerbose) {
@@ -1688,124 +1753,171 @@
@Override
public void isFieldClassificationEnabled(@NonNull IResultReceiver receiver)
throws RemoteException {
- final int userId = UserHandle.getCallingUserId();
boolean enabled = false;
+ final int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- enabled = service.isFieldClassificationEnabled(getCallingUid());
- } else if (sVerbose) {
- Slog.v(TAG, "isFieldClassificationEnabled(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ enabled = service.isFieldClassificationEnabled(getCallingUid());
+ } else if (sVerbose) {
+ Slog.v(TAG, "isFieldClassificationEnabled(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ // Do not raise the exception, just send back false
+ Log.wtf(TAG, "isFieldClassificationEnabled(): failed " + ex.toString());
+ } finally {
+ send(receiver, enabled);
}
- send(receiver, enabled);
}
@Override
public void getDefaultFieldClassificationAlgorithm(@NonNull IResultReceiver receiver)
throws RemoteException {
- final int userId = UserHandle.getCallingUserId();
String algorithm = null;
+ final int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- algorithm = service.getDefaultFieldClassificationAlgorithm(getCallingUid());
- } else {
- if (sVerbose) {
- Slog.v(TAG, "getDefaultFcAlgorithm(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ algorithm = service.getDefaultFieldClassificationAlgorithm(getCallingUid());
+ } else {
+ if (sVerbose) {
+ Slog.v(TAG, "getDefaultFcAlgorithm(): no service for " + userId);
+ }
}
- }
+ }
+ } catch (Exception ex) {
+ // Do not raise the exception, just send back null
+ Log.wtf(TAG, "getDefaultFieldClassificationAlgorithm(): failed " + ex.toString());
+ } finally {
+ send(receiver, algorithm);
}
- send(receiver, algorithm);
+
}
@Override
public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities, @NonNull IResultReceiver receiver)
throws RemoteException {
+ boolean ok = false;
final int userId = UserHandle.getCallingUserId();
- boolean ok;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- ok = service.setAugmentedAutofillWhitelistLocked(packages, activities,
- getCallingUid());
- } else {
- if (sVerbose) {
- Slog.v(TAG, "setAugmentedAutofillWhitelist(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ ok = service.setAugmentedAutofillWhitelistLocked(packages, activities,
+ getCallingUid());
+ } else {
+ if (sVerbose) {
+ Slog.v(TAG, "setAugmentedAutofillWhitelist(): no service for "
+ + userId);
+ }
}
- ok = false;
}
+ } catch (Exception ex) {
+ // Do not raise the exception, return the default value
+ Log.wtf(TAG, "setAugmentedAutofillWhitelist(): failed " + ex.toString());
+ } finally {
+ send(receiver,
+ ok ? AutofillManager.RESULT_OK
+ : AutofillManager.RESULT_CODE_NOT_SERVICE);
}
- send(receiver,
- ok ? AutofillManager.RESULT_OK : AutofillManager.RESULT_CODE_NOT_SERVICE);
}
@Override
public void getAvailableFieldClassificationAlgorithms(@NonNull IResultReceiver receiver)
throws RemoteException {
- final int userId = UserHandle.getCallingUserId();
String[] algorithms = null;
+ final int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- algorithms = service.getAvailableFieldClassificationAlgorithms(getCallingUid());
- } else {
- if (sVerbose) {
- Slog.v(TAG, "getAvailableFcAlgorithms(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ algorithms = service
+ .getAvailableFieldClassificationAlgorithms(getCallingUid());
+ } else {
+ if (sVerbose) {
+ Slog.v(TAG, "getAvailableFcAlgorithms(): no service for " + userId);
+ }
}
}
+ } catch (Exception ex) {
+ // Do not raise the exception, return null
+ Log.wtf(TAG, "getAvailableFieldClassificationAlgorithms(): failed "
+ + ex.toString());
+ } finally {
+ send(receiver, algorithms);
}
- send(receiver, algorithms);
}
@Override
public void getAutofillServiceComponentName(@NonNull IResultReceiver receiver)
throws RemoteException {
+ ComponentName componentName = null;
final int userId = UserHandle.getCallingUserId();
- ComponentName componentName = null;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- componentName = service.getServiceComponentName();
- } else if (sVerbose) {
- Slog.v(TAG, "getAutofillServiceComponentName(): no service for " + userId);
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ componentName = service.getServiceComponentName();
+ } else if (sVerbose) {
+ Slog.v(TAG, "getAutofillServiceComponentName(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ Log.wtf(TAG, "getAutofillServiceComponentName(): failed " + ex.toString());
+ } finally {
+ send(receiver, componentName);
}
- send(receiver, componentName);
}
@Override
public void restoreSession(int sessionId, @NonNull IBinder activityToken,
@NonNull IBinder appCallback, @NonNull IResultReceiver receiver)
throws RemoteException {
- final int userId = UserHandle.getCallingUserId();
- Objects.requireNonNull(activityToken, "activityToken");
- Objects.requireNonNull(appCallback, "appCallback");
-
boolean restored = false;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- restored = service.restoreSession(sessionId, getCallingUid(), activityToken,
- appCallback);
- } else if (sVerbose) {
- Slog.v(TAG, "restoreSession(): no service for " + userId);
+ final int userId = UserHandle.getCallingUserId();
+
+ try {
+ Objects.requireNonNull(activityToken, "activityToken");
+ Objects.requireNonNull(appCallback, "appCallback");
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ if (service != null) {
+ restored = service.restoreSession(sessionId, getCallingUid(), activityToken,
+ appCallback);
+ } else if (sVerbose) {
+ Slog.v(TAG, "restoreSession(): no service for " + userId);
+ }
}
+ } catch (Exception ex) {
+ // Do not propagate exception, send back status
+ Log.wtf(TAG, "restoreSession(): failed " + ex.toString());
+ } finally {
+ send(receiver, restored);
}
- send(receiver, restored);
}
@Override
public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
AutofillValue value, int action, int flags, int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
value, action, flags);
@@ -1818,7 +1930,8 @@
@Override
public void setAutofillFailure(int sessionId, @NonNull List<AutofillId> ids, int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.setAutofillFailureLocked(sessionId, getCallingUid(), ids);
} else if (sVerbose) {
@@ -1831,7 +1944,8 @@
public void finishSession(int sessionId, int userId,
@AutofillCommitReason int commitReason) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.finishSessionLocked(sessionId, getCallingUid(), commitReason);
} else if (sVerbose) {
@@ -1843,19 +1957,22 @@
@Override
public void cancelSession(int sessionId, int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.cancelSessionLocked(sessionId, getCallingUid());
} else if (sVerbose) {
Slog.v(TAG, "cancelSession(): no service for " + userId);
}
}
+
}
@Override
public void disableOwnedAutofillServices(int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
service.disableOwnedAutofillServicesLocked(Binder.getCallingUid());
} else if (sVerbose) {
@@ -1867,21 +1984,36 @@
@Override
public void isServiceSupported(int userId, @NonNull IResultReceiver receiver) {
boolean supported = false;
- synchronized (mLock) {
- supported = !isDisabledLocked(userId);
+
+ try {
+ synchronized (mLock) {
+ supported = !isDisabledLocked(userId);
+ }
+ } catch (Exception ex) {
+ // Do not propagate exception
+ Log.wtf(TAG, "isServiceSupported(): failed " + ex.toString());
+ } finally {
+ send(receiver, supported);
}
- send(receiver, supported);
}
@Override
public void isServiceEnabled(int userId, @NonNull String packageName,
@NonNull IResultReceiver receiver) {
boolean enabled = false;
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
- enabled = Objects.equals(packageName, service.getServicePackageName());
+
+ try {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(userId);
+ enabled = Objects.equals(packageName, service.getServicePackageName());
+ }
+ } catch (Exception ex) {
+ // Do not propagate exception
+ Log.wtf(TAG, "isServiceEnabled(): failed " + ex.toString());
+ } finally {
+ send(receiver, enabled);
}
- send(receiver, enabled);
}
@Override
@@ -1891,8 +2023,9 @@
|| operation == AutofillManager.PENDING_UI_OPERATION_RESTORE,
"invalid operation: %d", operation);
synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(
- UserHandle.getCallingUserId());
+ final AutofillManagerServiceImpl service =
+ peekServiceForUserWithLocalBinderIdentityLocked(
+ UserHandle.getCallingUserId());
if (service != null) {
service.onPendingSaveUi(operation, token);
}
@@ -1907,7 +2040,7 @@
boolean uiOnly = false;
if (args != null) {
for (String arg : args) {
- switch(arg) {
+ switch (arg) {
case "--no-history":
showHistory = false;
break;
@@ -1934,27 +2067,38 @@
try {
sDebug = sVerbose = true;
synchronized (mLock) {
- pw.print("sDebug: "); pw.print(realDebug);
- pw.print(" sVerbose: "); pw.println(realVerbose);
+ pw.print("sDebug: ");
+ pw.print(realDebug);
+ pw.print(" sVerbose: ");
+ pw.println(realVerbose);
pw.print("Flags: ");
synchronized (mFlagLock) {
- pw.print("mPccClassificationEnabled="); pw.print(mPccClassificationEnabled);
+ pw.print("mPccClassificationEnabled=");
+ pw.print(mPccClassificationEnabled);
pw.print(";");
- pw.print("mPccPreferProviderOverPcc="); pw.print(mPccPreferProviderOverPcc);
+ pw.print("mPccPreferProviderOverPcc=");
+ pw.print(mPccPreferProviderOverPcc);
pw.print(";");
- pw.print("mPccUseFallbackDetection="); pw.print(mPccUseFallbackDetection);
+ pw.print("mPccUseFallbackDetection=");
+ pw.print(mPccUseFallbackDetection);
pw.print(";");
- pw.print("mPccProviderHints="); pw.println(mPccProviderHints);
+ pw.print("mPccProviderHints=");
+ pw.println(mPccProviderHints);
}
// Dump per-user services
dumpLocked("", pw);
- mAugmentedAutofillResolver.dumpShort(pw); pw.println();
- pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
- pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount);
+ mAugmentedAutofillResolver.dumpShort(pw);
+ pw.println();
+ pw.print("Max partitions per session: ");
+ pw.println(sPartitionMaxCount);
+ pw.print("Max visible datasets: ");
+ pw.println(sVisibleDatasetsMaxCount);
if (sFullScreenMode != null) {
- pw.print("Overridden full-screen mode: "); pw.println(sFullScreenMode);
+ pw.print("Overridden full-screen mode: ");
+ pw.println(sFullScreenMode);
}
- pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw);
+ pw.println("User data constraints: ");
+ UserData.dumpConstraints(prefix, pw);
mUi.dump(pw);
pw.print("Autofill Compat State: ");
mAutofillCompatState.dump(prefix, pw);
@@ -1969,11 +2113,17 @@
pw.print("Augmented Service Request Timeout: ");
pw.println(mAugmentedServiceRequestTimeoutMs);
if (showHistory) {
- pw.println(); pw.println("Requests history:"); pw.println();
+ pw.println();
+ pw.println("Requests history:");
+ pw.println();
mRequestsHistory.reverseDump(fd, pw, args);
- pw.println(); pw.println("UI latency history:"); pw.println();
+ pw.println();
+ pw.println("UI latency history:");
+ pw.println();
mUiLatencyHistory.reverseDump(fd, pw, args);
- pw.println(); pw.println("WTF history:"); pw.println();
+ pw.println();
+ pw.println("WTF history:");
+ pw.println();
mWtfHistory.reverseDump(fd, pw, args);
}
pw.println("Augmented Autofill State: ");
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a5c4ac7..639f279 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -33,6 +33,7 @@
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_PCC_DETECTION;
import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE;
+import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
@@ -611,6 +612,9 @@
/** Whether the fill dialog UI is disabled. */
private boolean mFillDialogDisabled;
+
+ /** Whether current screen has credman field. */
+ private boolean mScreenHasCredmanField;
}
/**
@@ -3248,6 +3252,18 @@
final SaveInfo saveInfo = response == null ? null : response.getSaveInfo();
/*
+ * Don't show save if the session has credman field
+ */
+ if (mSessionFlags.mScreenHasCredmanField) {
+ if (sVerbose) {
+ Slog.v(TAG, "Call to Session#showSaveLocked() rejected - "
+ + "there is credman field in screen");
+ }
+ return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+ Event.NO_SAVE_UI_REASON_NONE);
+ }
+
+ /*
* The Save dialog is only shown if all conditions below are met:
*
* - saveInfo is not null.
@@ -3988,6 +4004,10 @@
return;
}
+ if ((flags & FLAG_SCREEN_HAS_CREDMAN_FIELD) != 0) {
+ mSessionFlags.mScreenHasCredmanField = true;
+ }
+
switch(action) {
case ACTION_START_SESSION:
// View is triggering autofill.
@@ -4466,7 +4486,7 @@
private boolean isFillDialogUiEnabled() {
synchronized (mLock) {
- return !mSessionFlags.mFillDialogDisabled;
+ return !mSessionFlags.mFillDialogDisabled && !mSessionFlags.mScreenHasCredmanField;
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index fb99bff..a831401 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -18,17 +18,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.sensor.IVirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.hardware.SensorDirectChannel;
+import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,6 +39,9 @@
import com.android.server.sensors.SensorManagerInternal;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@@ -54,46 +60,64 @@
private final Object mLock = new Object();
private final int mVirtualDeviceId;
+
@GuardedBy("mLock")
private final ArrayMap<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
+ // This device's sensors, keyed by sensor handle.
+ @GuardedBy("mLock")
+ private SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>();
+ @GuardedBy("mLock")
+ private List<VirtualSensor> mVirtualSensorList = null;
+
@NonNull
private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
private final SensorManagerInternal mSensorManagerInternal;
private final VirtualDeviceManagerInternal mVdmInternal;
- public SensorController(int virtualDeviceId,
- @Nullable IVirtualSensorCallback virtualSensorCallback) {
+ public SensorController(@NonNull IVirtualDevice virtualDevice, int virtualDeviceId,
+ @Nullable IVirtualSensorCallback virtualSensorCallback,
+ @NonNull List<VirtualSensorConfig> sensors) {
mVirtualDeviceId = virtualDeviceId;
mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
+ createSensors(virtualDevice, sensors);
}
void close() {
synchronized (mLock) {
mSensorDescriptors.values().forEach(
- descriptor -> mSensorManagerInternal.removeRuntimeSensor(
- descriptor.getHandle()));
+ descriptor -> mSensorManagerInternal.removeRuntimeSensor(descriptor.mHandle));
mSensorDescriptors.clear();
+ mVirtualSensors.clear();
+ mVirtualSensorList = null;
}
}
- int createSensor(@NonNull IBinder sensorToken, @NonNull VirtualSensorConfig config) {
- Objects.requireNonNull(sensorToken);
- Objects.requireNonNull(config);
+ private void createSensors(@NonNull IVirtualDevice virtualDevice,
+ @NonNull List<VirtualSensorConfig> configs) {
+ Objects.requireNonNull(virtualDevice);
+ final long token = Binder.clearCallingIdentity();
try {
- return createSensorInternal(sensorToken, config);
+ for (VirtualSensorConfig config : configs) {
+ createSensorInternal(virtualDevice, config);
+ }
} catch (SensorCreationException e) {
- throw new RuntimeException(
- "Failed to create virtual sensor '" + config.getName() + "'.", e);
+ throw new RuntimeException("Failed to create virtual sensor", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
- private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)
+ private void createSensorInternal(@NonNull IVirtualDevice virtualDevice,
+ @NonNull VirtualSensorConfig config)
throws SensorCreationException {
+ Objects.requireNonNull(config);
if (config.getType() <= 0) {
- throw new SensorCreationException("Received an invalid virtual sensor type.");
+ throw new SensorCreationException(
+ "Received an invalid virtual sensor type (config name '" + config.getName()
+ + "').");
}
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
config.getType(), config.getName(),
@@ -101,15 +125,20 @@
config.getResolution(), config.getPower(), config.getMinDelay(),
config.getMaxDelay(), config.getFlags(), mRuntimeSensorCallback);
if (handle <= 0) {
- throw new SensorCreationException("Received an invalid virtual sensor handle.");
+ throw new SensorCreationException(
+ "Received an invalid virtual sensor handle '" + config.getName() + "'.");
}
+ SensorDescriptor sensorDescriptor = new SensorDescriptor(
+ handle, config.getType(), config.getName());
+ final IBinder sensorToken =
+ new Binder("android.hardware.sensor.VirtualSensor:" + config.getName());
+ VirtualSensor sensor = new VirtualSensor(handle, config.getType(), config.getName(),
+ virtualDevice, sensorToken);
synchronized (mLock) {
- SensorDescriptor sensorDescriptor = new SensorDescriptor(
- handle, config.getType(), config.getName());
mSensorDescriptors.put(sensorToken, sensorDescriptor);
+ mVirtualSensors.put(handle, sensor);
}
- return handle;
}
boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
@@ -126,17 +155,25 @@
}
}
- void unregisterSensor(@NonNull IBinder token) {
- Objects.requireNonNull(token);
+ @Nullable
+ VirtualSensor getSensorByHandle(int handle) {
synchronized (mLock) {
- final SensorDescriptor sensorDescriptor = mSensorDescriptors.remove(token);
- if (sensorDescriptor == null) {
- throw new IllegalArgumentException("Could not unregister sensor for given token");
- }
- mSensorManagerInternal.removeRuntimeSensor(sensorDescriptor.getHandle());
+ return mVirtualSensors.get(handle);
}
}
+ List<VirtualSensor> getSensorList() {
+ synchronized (mLock) {
+ if (mVirtualSensorList == null) {
+ mVirtualSensorList = new ArrayList<>(mVirtualSensors.size());
+ for (int i = 0; i < mVirtualSensors.size(); ++i) {
+ mVirtualSensorList.add(mVirtualSensors.valueAt(i));
+ }
+ mVirtualSensorList = Collections.unmodifiableList(mVirtualSensorList);
+ }
+ return mVirtualSensorList;
+ }
+ }
void dump(@NonNull PrintWriter fout) {
fout.println(" SensorController: ");
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index e1b37e5..6b948bd 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -42,7 +42,6 @@
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
import android.companion.virtual.sensor.VirtualSensor;
-import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.content.ComponentName;
import android.content.Context;
@@ -94,7 +93,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -157,11 +155,6 @@
@GuardedBy("mVirtualDeviceLock")
@Nullable
private LocaleList mLocaleList = null;
- // This device's sensors, keyed by sensor handle.
- @GuardedBy("mVirtualDeviceLock")
- private SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>();
- @GuardedBy("mVirtualDeviceLock")
- private List<VirtualSensor> mVirtualSensorList = null;
private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@@ -218,7 +211,6 @@
ownerUid,
deviceId,
/* inputController= */ null,
- /* sensorController= */ null,
cameraAccessController,
pendingTrampolineCallback,
activityListener,
@@ -237,7 +229,6 @@
int ownerUid,
int deviceId,
InputController inputController,
- SensorController sensorController,
CameraAccessController cameraAccessController,
PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener,
@@ -266,15 +257,8 @@
} else {
mInputController = inputController;
}
- if (sensorController == null) {
- mSensorController = new SensorController(mDeviceId, mParams.getVirtualSensorCallback());
- } else {
- mSensorController = sensorController;
- }
- final List<VirtualSensorConfig> virtualSensorConfigs = mParams.getVirtualSensorConfigs();
- for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
- createVirtualSensor(virtualSensorConfigs.get(i));
- }
+ mSensorController = new SensorController(this, mDeviceId,
+ mParams.getVirtualSensorCallback(), mParams.getVirtualSensorConfigs());
mCameraAccessController = cameraAccessController;
mCameraAccessController.startObservingIfNeeded();
try {
@@ -284,6 +268,11 @@
}
}
+ @VisibleForTesting
+ SensorController getSensorControllerForTest() {
+ return mSensorController;
+ }
+
/**
* Returns the flags that should be added to any virtual displays created on this virtual
* device.
@@ -426,8 +415,6 @@
virtualDisplaysToBeReleased[i] = mVirtualDisplays.valueAt(i);
}
mVirtualDisplays.clear();
- mVirtualSensorList = null;
- mVirtualSensors.clear();
}
// Destroy the display outside locked section.
for (VirtualDisplayWrapper virtualDisplayWrapper : virtualDisplaysToBeReleased) {
@@ -723,43 +710,17 @@
}
}
- private void createVirtualSensor(@NonNull VirtualSensorConfig config) {
- final IBinder sensorToken =
- new Binder("android.hardware.sensor.VirtualSensor:" + config.getName());
- final long ident = Binder.clearCallingIdentity();
- try {
- int handle = mSensorController.createSensor(sensorToken, config);
- VirtualSensor sensor = new VirtualSensor(handle, config.getType(), config.getName(),
- this, sensorToken);
- synchronized (mVirtualDeviceLock) {
- mVirtualSensors.put(handle, sensor);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
@Override // Binder call
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Nullable
public List<VirtualSensor> getVirtualSensorList() {
super.getVirtualSensorList_enforcePermission();
- synchronized (mVirtualDeviceLock) {
- if (mVirtualSensorList == null) {
- mVirtualSensorList = new ArrayList<>();
- for (int i = 0; i < mVirtualSensors.size(); ++i) {
- mVirtualSensorList.add(mVirtualSensors.valueAt(i));
- }
- mVirtualSensorList = Collections.unmodifiableList(mVirtualSensorList);
- }
- return mVirtualSensorList;
- }
+ return mSensorController.getSensorList();
}
+ @Nullable
VirtualSensor getVirtualSensorByHandle(int handle) {
- synchronized (mVirtualDeviceLock) {
- return mVirtualSensors.get(handle);
- }
+ return mSensorController.getSensorByHandle(handle);
}
@Override // Binder call
@@ -960,7 +921,12 @@
"Virtual device doesn't have a virtual display with ID " + displayId);
}
- releaseOwnedVirtualDisplayResources(virtualDisplayWrapper);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ releaseOwnedVirtualDisplayResources(virtualDisplayWrapper);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
private void checkVirtualInputDeviceDisplayIdAssociation(int displayId) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index cfd9f16..ca1ab9b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -805,20 +805,7 @@
@Nullable
private ComponentName getContentProtectionServiceComponentName() {
String flatComponentName = getContentProtectionServiceFlatComponentName();
- ComponentName componentName = ComponentName.unflattenFromString(flatComponentName);
- if (componentName == null) {
- return null;
- }
-
- // Check permissions by trying to construct {@link ContentCaptureServiceInfo}
- try {
- createContentProtectionServiceInfo(componentName);
- } catch (Exception ex) {
- // Swallow, exception was already logged
- return null;
- }
-
- return componentName;
+ return ComponentName.unflattenFromString(flatComponentName);
}
/** @hide */
@@ -853,6 +840,15 @@
return null;
}
}
+
+ // Check permissions by trying to construct {@link ContentCaptureServiceInfo}
+ try {
+ createContentProtectionServiceInfo(mContentProtectionServiceComponentName);
+ } catch (Exception ex) {
+ // Swallow, exception was already logged
+ return null;
+ }
+
return createRemoteContentProtectionService(mContentProtectionServiceComponentName);
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
index f5e5a43..dd5545d 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
@@ -16,17 +16,15 @@
package com.android.server.contentprotection;
-import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED;
-
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentProtectionService;
import android.util.Slog;
import android.view.contentcapture.ContentCaptureEvent;
-import android.view.contentcapture.IContentCaptureDirectManager;
import com.android.internal.infra.ServiceConnector;
@@ -38,7 +36,7 @@
* @hide
*/
public class RemoteContentProtectionService
- extends ServiceConnector.Impl<IContentCaptureDirectManager> {
+ extends ServiceConnector.Impl<IContentProtectionService> {
private static final String TAG = RemoteContentProtectionService.class.getSimpleName();
@@ -57,7 +55,7 @@
.setComponent(componentName),
bindAllowInstant ? Context.BIND_ALLOW_INSTANT : 0,
userId,
- IContentCaptureDirectManager.Stub::asInterface);
+ IContentProtectionService.Stub::asInterface);
mComponentName = componentName;
}
@@ -68,7 +66,7 @@
@Override // from ServiceConnector.Impl
protected void onServiceConnectionStatusChanged(
- @NonNull IContentCaptureDirectManager service, boolean isConnected) {
+ @NonNull IContentProtectionService service, boolean isConnected) {
Slog.i(
TAG,
"Connection status for: "
@@ -78,9 +76,6 @@
}
public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
- run(
- service ->
- service.sendEvents(
- events, FLUSH_REASON_LOGIN_DETECTED, /* options= */ null));
+ run(service -> service.onLoginDetected(events));
}
}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 7d016c8..26421b7 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -313,6 +313,11 @@
private static final DropboxRateLimiter sDropboxRateLimiter = new DropboxRateLimiter();
+ /** Initialize the rate limiter. */
+ public static void initDropboxRateLimiter() {
+ sDropboxRateLimiter.init();
+ }
+
/**
* Reset the dropbox rate limiter.
*/
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 21a9a9f..1e3a5f4 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -60,6 +60,14 @@
// GWP-ASan's CTS test ensures that recoverable tombstones work,
// which is emitted by the NativeTombstoneManager.
"name": "CtsGwpAsanTestCases"
+ },
+ {
+ "name": "FrameworksVcnTests",
+ "file_patterns": ["VcnManagementService\\.java"]
+ },
+ {
+ "name": "CtsVcnTestCases",
+ "file_patterns": ["VcnManagementService\\.java"]
}
],
"presubmit-large": [
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index e8c85ce..c6e9a7d 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -162,6 +162,8 @@
// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
+ @NonNull private static final String CONTEXT_ATTRIBUTION_TAG = "VCN";
+
private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
private static final int LOCAL_LOG_LINE_COUNT = 512;
@@ -223,7 +225,9 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
- mContext = requireNonNull(context, "Missing context");
+ mContext =
+ requireNonNull(context, "Missing context")
+ .createAttributionContext(CONTEXT_ATTRIBUTION_TAG);
mDeps = requireNonNull(deps, "Missing dependencies");
mLooper = mDeps.getLooper();
@@ -1065,13 +1069,20 @@
boolean isRestricted = false;
synchronized (mLock) {
final Vcn vcn = mVcns.get(subGrp);
+ final VcnConfig vcnConfig = mConfigs.get(subGrp);
if (vcn != null) {
+ if (vcnConfig == null) {
+ // TODO: b/284381334 Investigate for the root cause of this issue
+ // and handle it properly
+ logWtf("Vcn instance exists but VcnConfig does not for " + subGrp);
+ }
+
if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) {
isVcnManagedNetwork = true;
}
final Set<Integer> restrictedTransports = mDeps.getRestrictedTransports(
- subGrp, mLastSnapshot, mConfigs.get(subGrp));
+ subGrp, mLastSnapshot, vcnConfig);
for (int restrictedTransport : restrictedTransports) {
if (ncCopy.hasTransport(restrictedTransport)) {
if (restrictedTransport == TRANSPORT_CELLULAR
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 9b4f968..0d423d8 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -80,6 +80,7 @@
*/
public class VpnManagerService extends IVpnManager.Stub {
private static final String TAG = VpnManagerService.class.getSimpleName();
+ private static final String CONTEXT_ATTRIBUTION_TAG = "VPN_MANAGER";
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -157,7 +158,7 @@
}
public VpnManagerService(Context context, Dependencies deps) {
- mContext = context;
+ mContext = context.createAttributionContext(CONTEXT_ATTRIBUTION_TAG);
mDeps = deps;
mHandlerThread = mDeps.makeHandlerThread();
mHandlerThread.start();
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 62651dd..ae12258 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -142,6 +142,7 @@
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.gnss@1.0::IGnss",
"android.hardware.graphics.allocator@2.0::IAllocator",
+ "android.hardware.graphics.allocator@4.0::IAllocator",
"android.hardware.graphics.composer@2.1::IComposer",
"android.hardware.health@2.0::IHealth",
"android.hardware.light@2.0::ILight",
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1f8a499..9474fc1 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -71,6 +71,7 @@
import android.content.pm.SigningDetails.CertCapabilities;
import android.content.pm.UserInfo;
import android.database.Cursor;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
@@ -1419,7 +1420,13 @@
private void purgeOldGrants(UserAccounts accounts) {
synchronized (accounts.dbLock) {
synchronized (accounts.cacheLock) {
- List<Integer> uids = accounts.accountsDb.findAllUidGrants();
+ List<Integer> uids;
+ try {
+ uids = accounts.accountsDb.findAllUidGrants();
+ } catch (SQLiteCantOpenDatabaseException e) {
+ Log.w(TAG, "Could not delete grants for user = " + accounts.userId);
+ return;
+ }
for (int uid : uids) {
final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
if (packageExists) {
@@ -1445,7 +1452,13 @@
mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
} catch (NameNotFoundException e) {
// package does not exist - remove visibility values
- accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
+ try {
+ accounts.accountsDb.deleteAccountVisibilityForPackage(packageName);
+ } catch (SQLiteCantOpenDatabaseException sqlException) {
+ Log.w(TAG, "Could not delete account visibility for user = "
+ + accounts.userId, sqlException);
+ continue;
+ }
synchronized (accounts.dbLock) {
synchronized (accounts.cacheLock) {
for (Account account : accounts.visibilityCache.keySet()) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d4845aa..12de0d7 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -621,7 +621,8 @@
try {
final ServiceRecord.StartItem si = r.pendingStarts.get(0);
startServiceInnerLocked(this, si.intent, r, false, true, si.callingId,
- si.mCallingProcessName, r.startRequested, si.mCallingPackageName);
+ si.mCallingProcessName, si.mCallingProcessState,
+ r.startRequested, si.mCallingPackageName);
} catch (TransactionTooLargeException e) {
// Ignore, nobody upstack cares.
}
@@ -977,10 +978,22 @@
fgRequired = false;
}
+ final ProcessRecord callingApp;
+ synchronized (mAm.mPidsSelfLocked) {
+ callingApp = mAm.mPidsSelfLocked.get(callingPid);
+ }
+ final String callingProcessName = callingApp != null
+ ? callingApp.processName : callingPackage;
+ final int callingProcessState =
+ callingApp != null && callingApp.getThread() != null && !callingApp.isKilled()
+ ? callingApp.mState.getCurProcState() : ActivityManager.PROCESS_STATE_UNKNOWN;
+ r.updateProcessStateOnRequest();
+
// The package could be frozen (meaning it's doing surgery), defer the actual
// start until the package is unfrozen.
if (deferServiceBringupIfFrozenLocked(r, service, callingPackage, callingFeatureId,
- callingUid, callingPid, fgRequired, callerFg, userId,
+ callingUid, callingPid, callingProcessName,
+ callingProcessState, fgRequired, callerFg, userId,
backgroundStartPrivileges, false, null)) {
return null;
}
@@ -1001,7 +1014,7 @@
// what realResult contains.
final ComponentName realResult =
startServiceInnerLocked(r, service, callingUid, callingPid,
- getCallingProcessNameLocked(callingUid, callingPid, callingPackage),
+ callingProcessName, callingProcessState,
fgRequired, callerFg,
backgroundStartPrivileges, callingPackage);
if (res.aliasComponent != null
@@ -1013,17 +1026,9 @@
}
}
- private String getCallingProcessNameLocked(int callingUid, int callingPid,
- String callingPackage) {
- synchronized (mAm.mPidsSelfLocked) {
- final ProcessRecord callingApp = mAm.mPidsSelfLocked.get(callingPid);
- return callingApp != null ? callingApp.processName : callingPackage;
- }
- }
-
private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
- int callingUid, int callingPid, String callingProcessName, boolean fgRequired,
- boolean callerFg,
+ int callingUid, int callingPid, String callingProcessName,
+ int callingProcessState, boolean fgRequired, boolean callerFg,
BackgroundStartPrivileges backgroundStartPrivileges, String callingPackage)
throws TransactionTooLargeException {
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
@@ -1037,7 +1042,8 @@
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
- service, neededGrants, callingUid, callingProcessName, callingPackage));
+ service, neededGrants, callingUid, callingProcessName, callingPackage,
+ callingProcessState));
// We want to allow scheduling user-initiated jobs when the app is running a
// foreground service that was started in the same conditions that allows for scheduling
@@ -1140,7 +1146,8 @@
r.allowBgActivityStartsOnServiceStart(backgroundStartPrivileges);
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting,
- callingUid, callingProcessName, wasStartRequested, callingPackage);
+ callingUid, callingProcessName, callingProcessState,
+ wasStartRequested, callingPackage);
return cmp;
}
@@ -1244,7 +1251,8 @@
@GuardedBy("mAm")
private boolean deferServiceBringupIfFrozenLocked(ServiceRecord s, Intent serviceIntent,
String callingPackage, @Nullable String callingFeatureId,
- int callingUid, int callingPid, boolean fgRequired, boolean callerFg, int userId,
+ int callingUid, int callingPid, String callingProcessName,
+ int callingProcessState, boolean fgRequired, boolean callerFg, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
boolean isBinding, IServiceConnection connection) {
final PackageManagerInternal pm = mAm.getPackageManagerInternal();
@@ -1258,8 +1266,6 @@
curPendingBringups = new ArrayList<>();
mPendingBringups.put(s, curPendingBringups);
}
- final String callingProcessName = getCallingProcessNameLocked(
- callingUid, callingPid, callingPackage);
curPendingBringups.add(new Runnable() {
@Override
public void run() {
@@ -1291,7 +1297,7 @@
} else { // Starting a service
try {
startServiceInnerLocked(s, serviceIntent, callingUid, callingPid,
- callingProcessName, fgRequired, callerFg,
+ callingProcessName, callingProcessState, fgRequired, callerFg,
backgroundStartPrivileges, callingPackage);
} catch (TransactionTooLargeException e) {
/* ignore - local call */
@@ -1338,7 +1344,8 @@
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting, int callingUid, String callingProcessName,
- boolean wasStartRequested, String callingPackage) throws TransactionTooLargeException {
+ int callingProcessState, boolean wasStartRequested, String callingPackage)
+ throws TransactionTooLargeException {
synchronized (mAm.mProcessStats.mLock) {
final ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1381,7 +1388,9 @@
getShortServiceNameForStats(r),
packageState,
packageName,
- callingPackage);
+ callingPackage,
+ callingProcessState,
+ r.mProcessStateOnRequest);
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
@@ -2156,9 +2165,7 @@
}
}
- final boolean fgsTypeChangingFromShortFgs = r.isForeground && isOldTypeShortFgs;
-
- if (fgsTypeChangingFromShortFgs) {
+ if (r.isForeground && isOldTypeShortFgs) {
// If we get here, that means startForeground(SHORT_SERVICE) is called again
// on a SHORT_SERVICE FGS.
@@ -2211,9 +2218,7 @@
// "if (r.mAllowStartForeground == REASON_DENIED...)" block below.
}
}
- }
-
- if (!fgsTypeChangingFromShortFgs && r.mStartForegroundCount == 0) {
+ } else if (r.mStartForegroundCount == 0) {
/*
If the service was started with startService(), not
startForegroundService(), and if startForeground() isn't called within
@@ -2244,7 +2249,7 @@
r.mLoggedInfoAllowStartForeground = false;
}
}
- } else if (!fgsTypeChangingFromShortFgs && r.mStartForegroundCount >= 1) {
+ } else if (r.mStartForegroundCount >= 1) {
// We get here if startForeground() is called multiple times
// on the same service after it's created, regardless of whether
// stopForeground() has been called or not.
@@ -3615,11 +3620,22 @@
return 0;
}
+ final ProcessRecord callingApp;
+ synchronized (mAm.mPidsSelfLocked) {
+ callingApp = mAm.mPidsSelfLocked.get(callingPid);
+ }
+ final String callingProcessName = callingApp != null
+ ? callingApp.processName : callingPackage;
+ final int callingProcessState =
+ callingApp != null && callingApp.getThread() != null && !callingApp.isKilled()
+ ? callingApp.mState.getCurProcState() : ActivityManager.PROCESS_STATE_UNKNOWN;
+ s.updateProcessStateOnRequest();
+
// The package could be frozen (meaning it's doing surgery), defer the actual
// binding until the package is unfrozen.
boolean packageFrozen = deferServiceBringupIfFrozenLocked(s, service, callingPackage, null,
- callingUid, callingPid, false, callerFg, userId, BackgroundStartPrivileges.NONE,
- true, connection);
+ callingUid, callingPid, callingProcessName, callingProcessState,
+ false, callerFg, userId, BackgroundStartPrivileges.NONE, true, connection);
// If permissions need a review before any of the app components can run,
// we schedule binding to the service but do not start its process, then
@@ -3760,7 +3776,9 @@
getShortServiceNameForStats(s),
packageState,
s.packageName,
- callerApp.info.packageName);
+ callerApp.info.packageName,
+ callerApp.mState.getCurProcState(),
+ s.mProcessStateOnRequest);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
+ ": received=" + b.intent.received
@@ -5359,7 +5377,7 @@
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
- null, null, 0, null, null));
+ null, null, 0, null, null, ActivityManager.PROCESS_STATE_UNKNOWN));
}
sendServiceArgsLocked(r, execInFg, true);
@@ -6355,7 +6373,8 @@
stopServiceLocked(sr, true);
} else {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
- sr.getLastStartId(), baseIntent, null, 0, null, null));
+ sr.getLastStartId(), baseIntent, null, 0, null, null,
+ ActivityManager.PROCESS_STATE_UNKNOWN));
if (sr.app != null && sr.app.getThread() != null) {
// We always run in the foreground, since this is called as
// part of the "remove task" UI operation.
@@ -7437,14 +7456,10 @@
r.mAllowWhileInUsePermissionInFgs = true;
}
- // Either (or both) mAllowWhileInUsePermissionInFgs or mAllowStartForeground is
- // newly allowed?
- boolean newlyAllowed = false;
if (!r.mAllowWhileInUsePermissionInFgs
|| (r.mAllowStartForeground == REASON_DENIED)) {
@ReasonCode final int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
- callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges,
- isBindService);
+ callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges);
// We store them to compare the old and new while-in-use logics to each other.
// (They're not used for any other purposes.)
if (!r.mAllowWhileInUsePermissionInFgs) {
@@ -7478,7 +7493,7 @@
}
final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
callingPackage, callingPid, callingUid, null /* targetProcess */,
- BackgroundStartPrivileges.NONE, false);
+ BackgroundStartPrivileges.NONE);
@ReasonCode int allowStartFgs = shouldAllowFgsStartForegroundNoBindingCheckLocked(
allowWhileInUse, callingPid, callingUid, callingPackage, null /* targetService */,
BackgroundStartPrivileges.NONE);
@@ -7502,19 +7517,15 @@
*/
private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
int callingPid, int callingUid, @Nullable ProcessRecord targetProcess,
- BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
+ BackgroundStartPrivileges backgroundStartPrivileges) {
int ret = REASON_DENIED;
- final boolean forStartForeground = !isBindService;
-
- if (forStartForeground) {
- final int uidState = mAm.getUidStateLocked(callingUid);
- if (ret == REASON_DENIED) {
- // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT,
- // PROCESS_STATE_PERSISTENT_UI or PROCESS_STATE_TOP.
- if (uidState <= PROCESS_STATE_TOP) {
- ret = getReasonCodeFromProcState(uidState);
- }
+ final int uidState = mAm.getUidStateLocked(callingUid);
+ if (ret == REASON_DENIED) {
+ // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT,
+ // PROCESS_STATE_PERSISTENT_UI or PROCESS_STATE_TOP.
+ if (uidState <= PROCESS_STATE_TOP) {
+ ret = getReasonCodeFromProcState(uidState);
}
}
@@ -7735,7 +7746,7 @@
shouldAllowFgsWhileInUsePermissionLocked(
clientPackageName,
clientPid, clientUid, null /* targetProcess */,
- BackgroundStartPrivileges.NONE, false);
+ BackgroundStartPrivileges.NONE);
final @ReasonCode int allowStartFgs =
shouldAllowFgsStartForegroundNoBindingCheckLocked(
allowWhileInUse2,
@@ -8164,7 +8175,7 @@
String callingPackage) {
return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
/* targetProcess */ null,
- BackgroundStartPrivileges.NONE, false)
+ BackgroundStartPrivileges.NONE)
!= REASON_DENIED;
}
@@ -8172,7 +8183,7 @@
String callingPackage, @Nullable ProcessRecord targetProcess,
@NonNull BackgroundStartPrivileges backgroundStartPrivileges) {
return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
- targetProcess, backgroundStartPrivileges, false) != REASON_DENIED;
+ targetProcess, backgroundStartPrivileges) != REASON_DENIED;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 44e198b..c2a2423 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -1345,6 +1345,8 @@
// The following read from Settings.
updateActivityStartsLoggingEnabled();
updateForegroundServiceStartsLoggingEnabled();
+ // Read DropboxRateLimiter params from flags.
+ mService.initDropboxRateLimiter();
}
private void loadDeviceConfigConstants() {
@@ -1678,9 +1680,9 @@
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
- if (mKillBgRestrictedAndCachedIdleSettleTimeMs != currentSettleTime) {
- mService.mHandler.removeMessages(
- ActivityManagerService.IDLE_UIDS_MSG);
+ if (mKillBgRestrictedAndCachedIdleSettleTimeMs < currentSettleTime) {
+ // Don't remove existing messages in case other IDLE_UIDS_MSG initiators use lower
+ // delays, but send a new message if the settle time has decreased.
mService.mHandler.sendEmptyMessageDelayed(
ActivityManagerService.IDLE_UIDS_MSG,
mKillBgRestrictedAndCachedIdleSettleTimeMs);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6dd311a..fb82490 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1176,20 +1176,24 @@
public Intent intent;
public boolean deferUntilActive;
public int originalCallingUid;
+ /** The snapshot process state of the app who sent this broadcast */
+ public int originalCallingAppProcessState;
public static StickyBroadcast create(Intent intent, boolean deferUntilActive,
- int originalCallingUid) {
+ int originalCallingUid, int originalCallingAppProcessState) {
final StickyBroadcast b = new StickyBroadcast();
b.intent = intent;
b.deferUntilActive = deferUntilActive;
b.originalCallingUid = originalCallingUid;
+ b.originalCallingAppProcessState = originalCallingAppProcessState;
return b;
}
@Override
public String toString() {
return "{intent=" + intent + ", defer=" + deferUntilActive + ", originalCallingUid="
- + originalCallingUid + "}";
+ + originalCallingUid + ", originalCallingAppProcessState="
+ + originalCallingAppProcessState + "}";
}
}
@@ -1522,6 +1526,8 @@
*/
int mBootPhase;
+ volatile boolean mDeterministicUidIdle = false;
+
@VisibleForTesting
public WindowManagerService mWindowManager;
WindowManagerInternal mWmInternal;
@@ -1616,6 +1622,8 @@
static final int SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG = 77;
static final int SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG = 78;
static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79;
+ static final int ADD_UID_TO_OBSERVER_MSG = 80;
+ static final int REMOVE_UID_FROM_OBSERVER_MSG = 81;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1774,6 +1782,12 @@
case PUSH_TEMP_ALLOWLIST_UI_MSG: {
pushTempAllowlist();
} break;
+ case ADD_UID_TO_OBSERVER_MSG: {
+ mUidObserverController.addUidToObserverImpl((IBinder) msg.obj, msg.arg1);
+ } break;
+ case REMOVE_UID_FROM_OBSERVER_MSG: {
+ mUidObserverController.removeUidFromObserverImpl((IBinder) msg.obj, msg.arg1);
+ } break;
}
}
}
@@ -9206,6 +9220,11 @@
private final DropboxRateLimiter mDropboxRateLimiter = new DropboxRateLimiter();
+ /** Initializes the Dropbox Rate Limiter parameters from flags. */
+ public void initDropboxRateLimiter() {
+ mDropboxRateLimiter.init();
+ }
+
/**
* Write a description of an error (crash, WTF, ANR) to the drop box.
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
@@ -13794,7 +13813,8 @@
if (action.startsWith("android.intent.action.USER_")
|| action.startsWith("android.intent.action.PACKAGE_")
|| action.startsWith("android.intent.action.UID_")
- || action.startsWith("android.intent.action.EXTERNAL_")) {
+ || action.startsWith("android.intent.action.EXTERNAL_")
+ || action.startsWith("android.bluetooth.")) {
if (DEBUG_BROADCAST) {
Slog.wtf(TAG,
"System internals registering for " + filter.toLongString()
@@ -14042,7 +14062,8 @@
receivers, null, null, 0, null, null, false, true, true, -1,
originalStickyCallingUid, BackgroundStartPrivileges.NONE,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
- null /* filterExtrasForReceiver */);
+ null /* filterExtrasForReceiver */,
+ broadcast.originalCallingAppProcessState);
queue.enqueueBroadcastLocked(r);
}
}
@@ -14857,6 +14878,7 @@
}
}
+ final int callerAppProcessState = getRealProcessStateLocked(callerApp, realCallingPid);
// Add to the sticky list if requested.
if (sticky) {
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
@@ -14919,12 +14941,13 @@
if (intent.filterEquals(list.get(i).intent)) {
// This sticky already exists, replace it.
list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive,
- callingUid));
+ callingUid, callerAppProcessState));
break;
}
}
if (i >= stickiesCount) {
- list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid));
+ list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid,
+ callerAppProcessState));
}
}
@@ -15007,7 +15030,8 @@
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
registeredReceivers, resultToApp, resultTo, resultCode, resultData,
resultExtras, ordered, sticky, false, userId,
- backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
+ backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
+ callerAppProcessState);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
queue.enqueueBroadcastLocked(r);
registeredReceivers = null;
@@ -15101,7 +15125,8 @@
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId,
- backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
+ backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
+ callerAppProcessState);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
queue.enqueueBroadcastLocked(r);
@@ -15118,6 +15143,19 @@
return ActivityManager.BROADCAST_SUCCESS;
}
+ @GuardedBy("this")
+ private int getRealProcessStateLocked(ProcessRecord app, int pid) {
+ if (app == null) {
+ synchronized (mPidsSelfLocked) {
+ app = mPidsSelfLocked.get(pid);
+ }
+ }
+ if (app != null && app.getThread() != null && !app.isKilled()) {
+ return app.mState.getCurProcState();
+ }
+ return PROCESS_STATE_NONEXISTENT;
+ }
+
@VisibleForTesting
ArrayList<StickyBroadcast> getStickyBroadcasts(String action, int userId) {
final ArrayMap<String, ArrayList<StickyBroadcast>> stickyBroadcasts =
@@ -16472,6 +16510,11 @@
}
}
+ @Override
+ public void setDeterministicUidIdle(boolean deterministic) {
+ mDeterministicUidIdle = deterministic;
+ }
+
/** Make the currently active UIDs idle after a certain grace period. */
final void idleUids() {
synchronized (this) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d61c3f7..5be3383 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -149,7 +149,6 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
@@ -293,6 +292,8 @@
return runKillAll(pw);
case "make-uid-idle":
return runMakeIdle(pw);
+ case "set-deterministic-uid-idle":
+ return runSetDeterministicUidIdle(pw);
case "monitor":
return runMonitor(pw);
case "watch-uids":
@@ -610,15 +611,7 @@
return 1;
}
- AtomicReference<String> mimeType = new AtomicReference<>(intent.getType());
-
- if (mimeType.get() == null && intent.getData() != null
- && "content".equals(intent.getData().getScheme())) {
- mInterface.getMimeTypeFilterAsync(intent.getData(), mUserId,
- new RemoteCallback(result -> {
- mimeType.set(result.getPairValue());
- }));
- }
+ final String mimeType = intent.resolveType(mInternal.mContext);
do {
if (mStopOption) {
@@ -630,7 +623,7 @@
int userIdForQuery = mInternal.mUserController.handleIncomingUser(
Binder.getCallingPid(), Binder.getCallingUid(), mUserId, false,
ALLOW_NON_FULL, "ActivityManagerShellCommand", null);
- List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType.get(),
+ List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType,
0, userIdForQuery).getList();
if (activities == null || activities.size() <= 0) {
getErrPrintWriter().println("Error: Intent does not match any activities: "
@@ -727,12 +720,12 @@
}
if (mWaitOption) {
result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
- mimeType.get(), null, null, 0, mStartFlags, profilerInfo,
+ mimeType, null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
res = result.result;
} else {
res = mInternal.startActivityAsUserWithFeature(null, SHELL_PACKAGE_NAME, null,
- intent, mimeType.get(), null, null, 0, mStartFlags, profilerInfo,
+ intent, mimeType, null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
}
final long endTime = SystemClock.uptimeMillis();
@@ -1523,6 +1516,23 @@
return 0;
}
+ int runSetDeterministicUidIdle(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_ALL;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ boolean deterministic = Boolean.parseBoolean(getNextArgRequired());
+ mInterface.setDeterministicUidIdle(deterministic);
+ return 0;
+ }
+
static final class MyActivityController extends IActivityController.Stub {
final IActivityManager mInterface;
final PrintWriter mPw;
@@ -4274,6 +4284,11 @@
pw.println(" make-uid-idle [--user <USER_ID> | all | current] <PACKAGE>");
pw.println(" If the given application's uid is in the background and waiting to");
pw.println(" become idle (not allowing background services), do that now.");
+ pw.println(
+ " set-deterministic-uid-idle [--user <USER_ID> | all | current] <true|false>");
+ pw.println(" If true, sets the timing of making UIDs idle consistent and");
+ pw.println(" deterministic. If false, the timing will be variable depending on");
+ pw.println(" other activity on the device. The default is false.");
pw.println(" monitor [--gdb <port>] [-p <TARGET>] [-s] [-c] [-k]");
pw.println(" Start monitoring for crashes or ANRs.");
pw.println(" --gdb: start gdbserv on the given port at crash/ANR");
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 4b6d324..a80ad59 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -106,6 +106,12 @@
long lastCpuDelayTime;
/**
+ * Snapshotted value of {@link ProcessStateRecord#getCurProcState()} before
+ * dispatching the current broadcast to the receiver in this process.
+ */
+ int lastProcessState;
+
+ /**
* Ordered collection of broadcasts that are waiting to be dispatched to
* this process, as a pair of {@link BroadcastRecord} and the index into
* {@link BroadcastRecord#receivers} that represents the receiver.
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index c6165cd..f13dc89 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -269,7 +269,10 @@
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.shareIdentity, oldRecord.userId,
oldRecord.callingUid, r.callingUid, r.callerPackage,
- SystemClock.uptimeMillis() - oldRecord.enqueueTime, 0);
+ SystemClock.uptimeMillis() - oldRecord.enqueueTime, 0, 0,
+ oldRecord.resultToApp != null
+ ? oldRecord.resultToApp.mState.getCurProcState()
+ : ActivityManager.PROCESS_STATE_UNKNOWN);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ mQueueName + "] sending broadcast result of "
@@ -367,6 +370,7 @@
}
r.curApp = app;
+ r.curAppLastProcessState = app.mState.getCurProcState();
final ProcessReceiverRecord prr = app.mReceivers;
prr.addCurReceiver(r);
app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
@@ -418,6 +422,7 @@
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
r.curApp = null;
+ r.curAppLastProcessState = ActivityManager.PROCESS_STATE_UNKNOWN;
prr.removeCurReceiver(r);
}
}
@@ -617,7 +622,11 @@
r.curApp.info.packageName,
r.callerPackage,
r.calculateTypeForLogging(),
- r.getDeliveryGroupPolicy());
+ r.getDeliveryGroupPolicy(),
+ r.intent.getFlags(),
+ BroadcastRecord.getReceiverPriority(curReceiver),
+ r.callerProcState,
+ r.curAppLastProcessState);
}
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG_BROADCAST, "finishReceiver [" + mQueueName + "] called but state is IDLE");
@@ -679,6 +688,7 @@
r.curFilter = null;
r.curReceiver = null;
r.curApp = null;
+ r.curAppLastProcessState = ActivityManager.PROCESS_STATE_UNKNOWN;
r.curFilteredExtras = null;
r.mWasReceiverAppStopped = false;
mPendingBroadcast = null;
@@ -748,7 +758,8 @@
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, boolean shareIdentity, int sendingUser,
int receiverUid, int callingUid, String callingPackage,
- long dispatchDelay, long receiveDelay) throws RemoteException {
+ long dispatchDelay, long receiveDelay, int priority,
+ int receiverProcessState) throws RemoteException {
// If the broadcaster opted-in to sharing their identity, then expose package visibility for
// the receiver.
if (shareIdentity) {
@@ -798,7 +809,8 @@
dispatchDelay, receiveDelay, 0 /* finish_delay */,
SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL,
app != null ? app.info.packageName : null, callingPackage,
- r.calculateTypeForLogging(), r.getDeliveryGroupPolicy());
+ r.calculateTypeForLogging(), r.getDeliveryGroupPolicy(), r.intent.getFlags(),
+ priority, r.callerProcState, receiverProcessState);
}
}
@@ -845,6 +857,7 @@
// things that directly call the IActivityManager API, which
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
+ r.curAppLastProcessState = r.curApp.mState.getCurProcState();
filter.receiverList.app.mReceivers.addCurReceiver(r);
mService.enqueueOomAdjTargetLocked(r.curApp);
mService.updateOomAdjPendingTargetsLocked(
@@ -879,7 +892,10 @@
r.resultExtras, r.ordered, r.initialSticky, r.shareIdentity, r.userId,
filter.receiverList.uid, r.callingUid, r.callerPackage,
r.dispatchTime - r.enqueueTime,
- r.receiverTime - r.dispatchTime);
+ r.receiverTime - r.dispatchTime, filter.getPriority(),
+ filter.receiverList.app != null
+ ? filter.receiverList.app.mState.getCurProcState()
+ : ActivityManager.PROCESS_STATE_UNKNOWN);
// parallel broadcasts are fire-and-forget, not bookended by a call to
// finishReceiverLocked(), so we manage their activity-start token here
if (filter.receiverList.app != null
@@ -1170,7 +1186,10 @@
r.resultData, r.resultExtras, false, false, r.shareIdentity,
r.userId, r.callingUid, r.callingUid, r.callerPackage,
r.dispatchTime - r.enqueueTime,
- now - r.dispatchTime);
+ now - r.dispatchTime, 0,
+ r.resultToApp != null
+ ? r.resultToApp.mState.getCurProcState()
+ : ActivityManager.PROCESS_STATE_UNKNOWN);
logBootCompletedBroadcastCompletionLatencyIfPossible(r);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
@@ -1476,6 +1495,7 @@
r.intent.getAction(), r.getHostingRecordTriggerType()),
isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
(r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
+ r.curAppLastProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
if (r.curApp == null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5356fdf..5a81e2a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -33,6 +33,7 @@
import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
import static com.android.server.am.BroadcastProcessQueue.reasonToString;
import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
+import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED;
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
import static com.android.server.am.BroadcastRecord.getReceiverClassName;
import static com.android.server.am.BroadcastRecord.getReceiverPackageName;
@@ -68,6 +69,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.MathUtils;
@@ -213,6 +215,13 @@
new AtomicReference<>();
/**
+ * Container for holding the set of broadcast records that satisfied a certain criteria.
+ */
+ @GuardedBy("mService")
+ private final AtomicReference<ArrayMap<BroadcastRecord, Boolean>> mRecordsLookupCache =
+ new AtomicReference<>();
+
+ /**
* Map from UID to its last known "foreground" state. A UID is considered to be in
* "foreground" state when it's procState is {@link ActivityManager#PROCESS_STATE_TOP}.
* <p>
@@ -682,10 +691,10 @@
// If this receiver is going to be skipped, skip it now itself and don't even enqueue
// it.
- final boolean wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null);
- if (wouldBeSkipped) {
+ final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver);
+ if (skipReason != null) {
setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,
- "skipped by policy at enqueue");
+ "skipped by policy at enqueue: " + skipReason);
continue;
}
@@ -742,13 +751,16 @@
broadcastConsumer = mBroadcastConsumerSkipAndCanceled;
break;
case BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED:
+ // TODO: Allow applying MERGED policy for broadcasts with more than one receiver.
+ if (r.receivers.size() > 1) {
+ return;
+ }
final BundleMerger extrasMerger = r.options.getDeliveryGroupExtrasMerger();
if (extrasMerger == null) {
// Extras merger is required to be able to merge the extras. So, if it's not
// supplied, then ignore the delivery group policy.
return;
}
- // TODO: Don't merge with the same BroadcastRecord more than once.
broadcastConsumer = (record, recordIndex) -> {
r.intent.mergeExtras(record.intent, extrasMerger);
mBroadcastConsumerSkipAndCanceled.accept(record, recordIndex);
@@ -758,6 +770,7 @@
logw("Unknown delivery group policy: " + policy);
return;
}
+ final ArrayMap<BroadcastRecord, Boolean> recordsLookupCache = getRecordsLookupCache();
forEachMatchingBroadcast(QUEUE_PREDICATE_ANY, (testRecord, testIndex) -> {
// If the receiver is already in a terminal state, then ignore it.
if (isDeliveryStateTerminal(testRecord.getDeliveryState(testIndex))) {
@@ -769,22 +782,44 @@
|| !r.matchesDeliveryGroup(testRecord)) {
return false;
}
- // TODO: If a process is in a deferred state, we can always apply the policy as long
- // as it is one of the receivers for the new broadcast.
// For ordered broadcast, check if the receivers for the new broadcast is a superset
// of those for the previous one as skipping and removing only one of them could result
// in an inconsistent state.
- if (testRecord.ordered || testRecord.resultTo != null) {
- // TODO: Cache this result in some way so that we don't have to perform the
- // same check for all the broadcast receivers.
- return r.containsAllReceivers(testRecord.receivers);
- } else if (testRecord.prioritized) {
- return r.containsAllReceivers(testRecord.receivers);
+ if (testRecord.ordered || testRecord.prioritized) {
+ return containsAllReceivers(r, testRecord, recordsLookupCache);
+ } else if (testRecord.resultTo != null) {
+ return testRecord.getDeliveryState(testIndex) == DELIVERY_DEFERRED
+ ? r.containsReceiver(testRecord.receivers.get(testIndex))
+ : containsAllReceivers(r, testRecord, recordsLookupCache);
} else {
return r.containsReceiver(testRecord.receivers.get(testIndex));
}
}, broadcastConsumer, true);
+ recordsLookupCache.clear();
+ mRecordsLookupCache.compareAndSet(null, recordsLookupCache);
+ }
+
+ @NonNull
+ private ArrayMap<BroadcastRecord, Boolean> getRecordsLookupCache() {
+ ArrayMap<BroadcastRecord, Boolean> recordsLookupCache =
+ mRecordsLookupCache.getAndSet(null);
+ if (recordsLookupCache == null) {
+ recordsLookupCache = new ArrayMap<>();
+ }
+ return recordsLookupCache;
+ }
+
+ private boolean containsAllReceivers(@NonNull BroadcastRecord record,
+ @NonNull BroadcastRecord testRecord,
+ @NonNull ArrayMap<BroadcastRecord, Boolean> recordsLookupCache) {
+ final int idx = recordsLookupCache.indexOfKey(testRecord);
+ if (idx > 0) {
+ return recordsLookupCache.valueAt(idx);
+ }
+ final boolean containsAll = record.containsAllReceivers(testRecord.receivers);
+ recordsLookupCache.put(testRecord, containsAll);
+ return containsAll;
}
/**
@@ -1002,6 +1037,7 @@
mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent,
UserHandle.getAppId(app.uid), r.callingUid, true);
}
+ queue.lastProcessState = app.mState.getCurProcState();
if (receiver instanceof BroadcastFilter) {
notifyScheduleRegisteredReceiver(app, r, (BroadcastFilter) receiver);
thread.scheduleRegisteredReceiver(
@@ -1916,12 +1952,16 @@
? BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME
: BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST;
final int type;
+ final int receiverProcessState;
if (queue == null) {
type = BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_UNKNOWN;
+ receiverProcessState = ActivityManager.PROCESS_STATE_UNKNOWN;
} else if (queue.getActiveViaColdStart()) {
type = BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD;
+ receiverProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
} else {
type = BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM;
+ receiverProcessState = queue.lastProcessState;
}
// With the new per-process queues, there's no delay between being
// "dispatched" and "scheduled", so we report no "receive delay"
@@ -1935,7 +1975,9 @@
FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, uid, senderUid, actionName,
receiverType, type, dispatchDelay, receiveDelay, finishDelay, packageState,
app != null ? app.info.packageName : null, r.callerPackage,
- r.calculateTypeForLogging(), r.getDeliveryGroupPolicy());
+ r.calculateTypeForLogging(), r.getDeliveryGroupPolicy(), r.intent.getFlags(),
+ BroadcastRecord.getReceiverPriority(receiver), r.callerProcState,
+ receiverProcessState);
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index cfdb133..198adcb 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -44,6 +44,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
+import android.app.ActivityManager.ProcessState;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.BackgroundStartPrivileges;
@@ -93,6 +94,7 @@
final @Nullable String callerFeatureId; // which feature in the package sent this
final int callingPid; // the pid of who sent this
final int callingUid; // the uid of who sent this
+ final @ProcessState int callerProcState; // Procstate of the caller process at enqueue time.
final int originalStickyCallingUid;
// if this is a sticky broadcast, the Uid of the original sender
@@ -268,6 +270,8 @@
BroadcastFilter curFilter; // the registered receiver currently running.
Bundle curFilteredExtras; // the bundle that has been filtered by the package visibility rules
+ int curAppLastProcessState; // The last process state of the current receiver before receiving
+
boolean mIsReceiverAppRunning; // Was the receiver's app already running.
boolean mWasReceiverAppStopped; // Was the receiver app stopped prior to starting
@@ -429,13 +433,14 @@
boolean initialSticky, int userId,
@NonNull BackgroundStartPrivileges backgroundStartPrivileges,
boolean timeoutExempt,
- @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
+ int callerAppProcessState) {
this(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid,
callingUid, callerInstantApp, resolvedType, requiredPermissions,
excludedPermissions, excludedPackages, appOp, options, receivers, resultToApp,
resultTo, resultCode, resultData, resultExtras, serialized, sticky,
initialSticky, userId, -1, backgroundStartPrivileges, timeoutExempt,
- filterExtrasForReceiver);
+ filterExtrasForReceiver, callerAppProcessState);
}
BroadcastRecord(BroadcastQueue _queue,
@@ -450,7 +455,8 @@
boolean _initialSticky, int _userId, int originalStickyCallingUid,
@NonNull BackgroundStartPrivileges backgroundStartPrivileges,
boolean timeoutExempt,
- @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver,
+ int callerAppProcessState) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -462,6 +468,7 @@
callerFeatureId = _callerFeatureId;
callingPid = _callingPid;
callingUid = _callingUid;
+ callerProcState = callerAppProcessState;
callerInstantApp = _callerInstantApp;
callerInstrumented = isCallerInstrumented(_callerApp, _callingUid);
resolvedType = _resolvedType;
@@ -515,6 +522,7 @@
callerFeatureId = from.callerFeatureId;
callingPid = from.callingPid;
callingUid = from.callingUid;
+ callerProcState = from.callerProcState;
callerInstantApp = from.callerInstantApp;
callerInstrumented = from.callerInstrumented;
ordered = from.ordered;
@@ -600,7 +608,8 @@
requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
splitReceivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, initialSticky, userId,
- mBackgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver);
+ mBackgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
+ callerProcState);
split.enqueueTime = this.enqueueTime;
split.enqueueRealTime = this.enqueueRealTime;
split.enqueueClockTime = this.enqueueClockTime;
@@ -680,7 +689,7 @@
uid2receiverList.valueAt(i), null /* _resultToApp */, null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
mBackgroundStartPrivileges, timeoutExempt,
- filterExtrasForReceiver);
+ filterExtrasForReceiver, callerProcState);
br.enqueueTime = this.enqueueTime;
br.enqueueRealTime = this.enqueueRealTime;
br.enqueueClockTime = this.enqueueClockTime;
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 695ea4f..3ab40d2 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -246,9 +246,13 @@
}
}
+ final int callingProcessState = r != null
+ ? r.mState.getCurProcState() : ActivityManager.PROCESS_STATE_UNKNOWN;
+
if (providerRunning) {
cpi = cpr.info;
+
if (r != null && cpr.canRunHere(r)) {
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
cpr.name.flattenToShortString(), startTime);
@@ -265,7 +269,8 @@
r.uid, callingUid,
PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM,
PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL,
- cpi.packageName, callingPackage);
+ cpi.packageName, callingPackage,
+ callingProcessState, callingProcessState);
return holder;
}
@@ -281,6 +286,8 @@
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
cpr.name.flattenToShortString(), startTime);
+ final int providerProcessState = cpr.proc.mState.getCurProcState();
+
final long origId = Binder.clearCallingIdentity();
try {
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
@@ -337,7 +344,8 @@
cpr.proc.uid, callingUid,
PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM,
PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL,
- cpi.packageName, callingPackage);
+ cpi.packageName, callingPackage,
+ callingProcessState, providerProcessState);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -514,7 +522,8 @@
proc.uid, callingUid,
PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM,
PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL,
- cpi.packageName, callingPackage);
+ cpi.packageName, callingPackage,
+ callingProcessState, proc.mState.getCurProcState());
} else {
final int packageState =
((cpr.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0)
@@ -539,7 +548,8 @@
PROVIDER_ACQUISITION_EVENT_REPORTED,
proc.uid, callingUid,
PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD,
- packageState, cpi.packageName, callingPackage);
+ packageState, cpi.packageName, callingPackage,
+ callingProcessState, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index b5c7215..003e614 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.os.SystemClock;
+import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Slog;
@@ -30,17 +31,26 @@
// After RATE_LIMIT_ALLOWED_ENTRIES have been collected (for a single breakdown of
// process/eventType) further entries will be rejected until RATE_LIMIT_BUFFER_DURATION has
// elapsed, after which the current count for this breakdown will be reset.
- private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.MINUTE_IN_MILLIS;
+ private static final long RATE_LIMIT_BUFFER_DURATION_DEFAULT = 10 * DateUtils.MINUTE_IN_MILLIS;
// Indicated how many buffer durations to wait before the rate limit buffer will be cleared.
// E.g. if set to 3 will wait 3xRATE_LIMIT_BUFFER_DURATION before clearing the buffer.
- private static final long RATE_LIMIT_BUFFER_EXPIRY_FACTOR = 3;
+ private static final long RATE_LIMIT_BUFFER_EXPIRY_FACTOR_DEFAULT = 3;
// The number of entries to keep per breakdown of process/eventType.
- private static final int RATE_LIMIT_ALLOWED_ENTRIES = 6;
+ private static final int RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT = 6;
// If a process is rate limited twice in a row we consider it crash-looping and rate limit it
// more aggressively.
- private static final int STRICT_RATE_LIMIT_ALLOWED_ENTRIES = 1;
- private static final long STRICT_RATE_LIMIT_BUFFER_DURATION = 20 * DateUtils.MINUTE_IN_MILLIS;
+ private static final int STRICT_RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT = 1;
+ private static final long STRICT_RATE_LIMIT_BUFFER_DURATION_DEFAULT =
+ 20 * DateUtils.MINUTE_IN_MILLIS;
+
+ private static final String FLAG_NAMESPACE = "dropbox";
+
+ private long mRateLimitBufferDuration;
+ private long mRateLimitBufferExpiryFactor;
+ private int mRateLimitAllowedEntries;
+ private int mStrictRatelimitAllowedEntries;
+ private long mStrictRateLimitBufferDuration;
@GuardedBy("mErrorClusterRecords")
private final ArrayMap<String, ErrorRecord> mErrorClusterRecords = new ArrayMap<>();
@@ -54,6 +64,36 @@
public DropboxRateLimiter(Clock clock) {
mClock = clock;
+
+ mRateLimitBufferDuration = RATE_LIMIT_BUFFER_DURATION_DEFAULT;
+ mRateLimitBufferExpiryFactor = RATE_LIMIT_BUFFER_EXPIRY_FACTOR_DEFAULT;
+ mRateLimitAllowedEntries = RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT;
+ mStrictRatelimitAllowedEntries = STRICT_RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT;
+ mStrictRateLimitBufferDuration = STRICT_RATE_LIMIT_BUFFER_DURATION_DEFAULT;
+ }
+
+ /** Initializes the rate limiter parameters from flags. */
+ public void init() {
+ mRateLimitBufferDuration = DeviceConfig.getLong(
+ FLAG_NAMESPACE,
+ "DropboxRateLimiter__rate_limit_buffer_duration",
+ RATE_LIMIT_BUFFER_DURATION_DEFAULT);
+ mRateLimitBufferExpiryFactor = DeviceConfig.getLong(
+ FLAG_NAMESPACE,
+ "DropboxRateLimiter__rate_limit_buffer_expiry_factor",
+ RATE_LIMIT_BUFFER_EXPIRY_FACTOR_DEFAULT);
+ mRateLimitAllowedEntries = DeviceConfig.getInt(
+ FLAG_NAMESPACE,
+ "DropboxRateLimiter__rate_limit_allowed_entries",
+ RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT);
+ mStrictRatelimitAllowedEntries = DeviceConfig.getInt(
+ FLAG_NAMESPACE,
+ "DropboxRateLimiter__strict_rate_limit_allowed_entries",
+ STRICT_RATE_LIMIT_ALLOWED_ENTRIES_DEFAULT);
+ mStrictRateLimitBufferDuration = DeviceConfig.getLong(
+ FLAG_NAMESPACE,
+ "DropboxRateLimiter__strict_rate_limit_buffer_duration",
+ STRICT_RATE_LIMIT_BUFFER_DURATION_DEFAULT);
}
/** The interface clock to use for tracking the time elapsed. */
@@ -116,7 +156,7 @@
private void maybeRemoveExpiredRecords(long currentTime) {
if (currentTime - mLastMapCleanUp
- <= RATE_LIMIT_BUFFER_EXPIRY_FACTOR * RATE_LIMIT_BUFFER_DURATION) {
+ <= mRateLimitBufferExpiryFactor * mRateLimitBufferDuration) {
return;
}
@@ -219,15 +259,15 @@
}
public int getAllowedEntries() {
- return isRepeated() ? STRICT_RATE_LIMIT_ALLOWED_ENTRIES : RATE_LIMIT_ALLOWED_ENTRIES;
+ return isRepeated() ? mStrictRatelimitAllowedEntries : mRateLimitAllowedEntries;
}
public long getBufferDuration() {
- return isRepeated() ? STRICT_RATE_LIMIT_BUFFER_DURATION : RATE_LIMIT_BUFFER_DURATION;
+ return isRepeated() ? mStrictRateLimitBufferDuration : mRateLimitBufferDuration;
}
public boolean hasExpired(long currentTime) {
- long bufferExpiry = RATE_LIMIT_BUFFER_EXPIRY_FACTOR * getBufferDuration();
+ long bufferExpiry = mRateLimitBufferExpiryFactor * getBufferDuration();
return currentTime - mStartTime > bufferExpiry;
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index a86c2e3..764bbe8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1471,7 +1471,8 @@
if (!ActivityManager.isProcStateBackground(uidRec.getSetProcState())
|| uidRec.isSetAllowListed()) {
uidRec.setLastBackgroundTime(nowElapsed);
- if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ if (mService.mDeterministicUidIdle
+ || !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
// Note: the background settle time is in elapsed realtime, while
// the handler time base is uptime. All this means is that we may
// stop background uids later than we had intended, but that only
@@ -3227,7 +3228,8 @@
// (for states debouncing to avoid from thrashing).
state.setLastCanKillOnBgRestrictedAndIdleTime(nowElapsed);
// Kick off the delayed checkup message if needed.
- if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ if (mService.mDeterministicUidIdle
+ || !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
mConstants.mKillBgRestrictedAndCachedIdleSettleTimeMs);
}
@@ -3346,6 +3348,7 @@
@GuardedBy("mService")
void idleUidsLocked() {
final int N = mActiveUids.size();
+ mService.mHandler.removeMessages(IDLE_UIDS_MSG);
if (N <= 0) {
return;
}
@@ -3391,7 +3394,6 @@
}
}
if (nextTime > 0) {
- mService.mHandler.removeMessages(IDLE_UIDS_MSG);
mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4342cb9..c5776d8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2572,9 +2572,14 @@
// and did the cleanup before the actual death notification. Check the dying processes.
predecessor = mDyingProcesses.get(processName, info.uid);
if (predecessor != null) {
- if (app != null) {
+ // The process record could have existed but its pid is set to 0. In this case,
+ // the 'app' and 'predecessor' could end up pointing to the same instance;
+ // so make sure we check this case here.
+ if (app != null && app != predecessor) {
app.mPredecessor = predecessor;
predecessor.mSuccessor = app;
+ } else {
+ app = null;
}
Slog.w(TAG_PROCESSES, predecessor.toString() + " is attached to a previous process "
+ predecessor.getDyingPid());
@@ -5195,6 +5200,8 @@
mDyingProcesses.remove(app.processName, app.uid);
app.setDyingPid(0);
handlePrecedingAppDiedLocked(app);
+ // Remove from the LRU list if it's still there.
+ removeLruProcessLocked(app);
return true;
}
return false;
@@ -5243,7 +5250,9 @@
mAppsInBackgroundRestricted.add(app);
final long future = killAppIfBgRestrictedAndCachedIdleLocked(
app, nowElapsed);
- if (future > 0 && !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ if (future > 0
+ && (mService.mDeterministicUidIdle
+ || !mService.mHandler.hasMessages(IDLE_UIDS_MSG))) {
mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
future - nowElapsed);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d6495c7..267d246 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -669,6 +669,11 @@
return mOnewayThread;
}
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ int getCurProcState() {
+ return mState.getCurProcState();
+ }
+
@GuardedBy({"mService", "mProcLock"})
public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
mProfile.onProcessActive(thread, tracker);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index dccbb0a..50fe6d7 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
@@ -244,6 +245,11 @@
*/
long mRestartSchedulingTime;
+ /**
+ * The snapshot process state when the service is requested (either start or bind).
+ */
+ int mProcessStateOnRequest;
+
static class StartItem {
final ServiceRecord sr;
final boolean taskRemoved;
@@ -253,6 +259,7 @@
final Intent intent;
final NeededUriGrants neededGrants;
final @Nullable String mCallingPackageName;
+ final int mCallingProcessState;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
@@ -262,7 +269,8 @@
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id,
Intent _intent, NeededUriGrants _neededGrants, int _callingId,
- String callingProcessName, @Nullable String callingPackageName) {
+ String callingProcessName, @Nullable String callingPackageName,
+ int callingProcessState) {
sr = _sr;
taskRemoved = _taskRemoved;
id = _id;
@@ -271,6 +279,7 @@
callingId = _callingId;
mCallingProcessName = callingProcessName;
mCallingPackageName = callingPackageName;
+ mCallingProcessState = callingProcessState;
}
UriPermissionOwner getUriPermissionsLocked() {
@@ -873,6 +882,7 @@
app.mServices.updateHostingComonentTypeForBindingsLocked();
}
app = proc;
+ updateProcessStateOnRequest();
if (pendingConnectionGroup > 0 && proc != null) {
final ProcessServiceRecord psr = proc.mServices;
psr.setConnectionService(this);
@@ -899,6 +909,11 @@
}
}
+ void updateProcessStateOnRequest() {
+ mProcessStateOnRequest = app != null && app.getThread() != null && !app.isKilled()
+ ? app.mState.getCurProcState() : PROCESS_STATE_NONEXISTENT;
+ }
+
@NonNull
ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
return connections;
@@ -1061,12 +1076,13 @@
if (app == null) {
return;
}
- if (mBackgroundStartPrivilegesByStartMerged.allowsAny()
- || mIsAllowedBgActivityStartsByBinding) {
+ BackgroundStartPrivileges backgroundStartPrivileges =
+ getBackgroundStartPrivilegesWithExclusiveToken();
+ if (backgroundStartPrivileges.allowsAny()) {
// if the token is already there it's safe to "re-add it" - we're dealing with
// a set of Binder objects
app.addOrUpdateBackgroundStartPrivileges(this,
- getBackgroundStartPrivilegesWithExclusiveToken());
+ backgroundStartPrivileges);
} else {
app.removeBackgroundStartPrivileges(this);
}
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index d9553a3..d4fd830 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -392,11 +392,9 @@
if (TEMP_DUMP_TIME_LIMIT <= timeTaken) {
Slog.e(TAG, "Aborted stack trace dump (current primary pid=" + pid
+ "); deadline exceeded.");
- tmpTracesFile.delete();
if (latencyTracker != null) {
latencyTracker.dumpStackTracesTempFileTimedOut();
}
- return null;
}
if (DEBUG_ANR) {
Slog.d(TAG, "Done with primary pid " + pid + " in " + timeTaken + "ms"
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index a6677a5..7eeec32 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -30,6 +30,7 @@
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -104,40 +105,62 @@
}
}
- void addUidToObserver(@NonNull IBinder observerToken, int uid) {
- synchronized (mLock) {
- int i = mUidObservers.beginBroadcast();
- while (i-- > 0) {
- var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
- if (reg.getToken().equals(observerToken)) {
- reg.addUid(uid);
- break;
- }
-
- if (i == 0) {
- Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
- }
- }
- mUidObservers.finishBroadcast();
- }
+ final void addUidToObserver(@NonNull IBinder observerToken, int uid) {
+ Message msg = Message.obtain(mHandler, ActivityManagerService.ADD_UID_TO_OBSERVER_MSG,
+ uid, /*arg2*/ 0, observerToken);
+ mHandler.sendMessage(msg);
}
- void removeUidFromObserver(@NonNull IBinder observerToken, int uid) {
- synchronized (mLock) {
- int i = mUidObservers.beginBroadcast();
- while (i-- > 0) {
- var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
- if (reg.getToken().equals(observerToken)) {
- reg.removeUid(uid);
- break;
- }
-
- if (i == 0) {
- Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
- }
+ /**
+ * Add a uid to the list of uids an observer is interested in. Must be run on the same thread
+ * as mDispatchRunnable.
+ *
+ * @param observerToken The token identifier for a UidObserver
+ * @param uid The uid to add to the list of watched uids
+ */
+ public final void addUidToObserverImpl(@NonNull IBinder observerToken, int uid) {
+ int i = mUidObservers.beginBroadcast();
+ while (i-- > 0) {
+ var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ if (reg.getToken().equals(observerToken)) {
+ reg.addUid(uid);
+ break;
}
- mUidObservers.finishBroadcast();
+
+ if (i == 0) {
+ Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
+ }
}
+ mUidObservers.finishBroadcast();
+ }
+
+ final void removeUidFromObserver(@NonNull IBinder observerToken, int uid) {
+ Message msg = Message.obtain(mHandler, ActivityManagerService.REMOVE_UID_FROM_OBSERVER_MSG,
+ uid, /*arg2*/ 0, observerToken);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Remove a uid from the list of uids an observer is interested in. Must be run on the same
+ * thread as mDispatchRunnable.
+ *
+ * @param observerToken The token identifier for a UidObserver
+ * @param uid The uid to remove from the list of watched uids
+ */
+ public final void removeUidFromObserverImpl(@NonNull IBinder observerToken, int uid) {
+ int i = mUidObservers.beginBroadcast();
+ while (i-- > 0) {
+ var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ if (reg.getToken().equals(observerToken)) {
+ reg.removeUid(uid);
+ break;
+ }
+
+ if (i == 0) {
+ Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
+ }
+ }
+ mUidObservers.finishBroadcast();
}
int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0a44da3..1dff62e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -924,9 +924,14 @@
mSwitchedOps.put(switchCode,
ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
}
- mAppOpsCheckingService = new AppOpsCheckingServiceTracingDecorator(
- new AppOpsCheckingServiceImpl(
- storageFile, this, handler, context, mSwitchedOps));
+ if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
+ mAppOpsCheckingService = new AppOpsCheckingServiceTracingDecorator(
+ LocalServices.getService(AppOpsCheckingServiceInterface.class));
+ } else {
+ mAppOpsCheckingService = new AppOpsCheckingServiceTracingDecorator(
+ new AppOpsCheckingServiceImpl(storageFile, this, handler, context,
+ mSwitchedOps));
+ }
mAppOpsCheckingService.addAppOpsModeChangedListener(
new AppOpsCheckingServiceInterface.AppOpsModeChangedListener() {
@Override
@@ -944,8 +949,6 @@
packageName, code, mode, userId));
}
});
- //mAppOpsCheckingService = new AppOpsCheckingServiceLoggingDecorator(
- // LocalServices.getService(AppOpsCheckingServiceInterface.class));
mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler,
code -> notifyWatchersOfChange(code, UID_ANY));
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2ba5223..84fe12e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1018,13 +1018,15 @@
}
}
- /*package*/ void clearA2dpSuspended() {
+ /*package*/ void clearA2dpSuspended(boolean internalOnly) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "clearA2dpSuspended");
+ Log.v(TAG, "clearA2dpSuspended, internalOnly: " + internalOnly);
}
synchronized (mBluetoothAudioStateLock) {
mBluetoothA2dpSuspendedInt = false;
- mBluetoothA2dpSuspendedExt = false;
+ if (!internalOnly) {
+ mBluetoothA2dpSuspendedExt = false;
+ }
updateAudioHalBluetoothState();
}
}
@@ -1046,13 +1048,15 @@
}
}
- /*package*/ void clearLeAudioSuspended() {
+ /*package*/ void clearLeAudioSuspended(boolean internalOnly) {
if (AudioService.DEBUG_COMM_RTE) {
- Log.v(TAG, "clearLeAudioSuspended");
+ Log.v(TAG, "clearLeAudioSuspended, internalOnly: " + internalOnly);
}
synchronized (mBluetoothAudioStateLock) {
mBluetoothLeSuspendedInt = false;
- mBluetoothLeSuspendedExt = false;
+ if (!internalOnly) {
+ mBluetoothLeSuspendedExt = false;
+ }
updateAudioHalBluetoothState();
}
}
@@ -2214,6 +2218,7 @@
mDeviceInventory.removePreferredDevicesForStrategyInt(mAccessibilityStrategyId);
}
mDeviceInventory.applyConnectedDevicesRoles();
+ mDeviceInventory.reapplyExternalDevicesRoles();
} else {
mDeviceInventory.setPreferredDevicesForStrategyInt(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index d1cae49..ec85d57 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -361,23 +361,34 @@
AudioSystem.DEVICE_STATE_AVAILABLE,
di.mDeviceCodecFormat);
}
- mAppliedStrategyRoles.clear();
mAppliedStrategyRolesInt.clear();
- mAppliedPresetRoles.clear();
mAppliedPresetRolesInt.clear();
applyConnectedDevicesRoles_l();
}
+ reapplyExternalDevicesRoles();
+ }
+
+ /*package*/ void reapplyExternalDevicesRoles() {
+ synchronized (mDevicesLock) {
+ mAppliedStrategyRoles.clear();
+ mAppliedPresetRoles.clear();
+ }
synchronized (mPreferredDevices) {
mPreferredDevices.forEach((strategy, devices) -> {
- setPreferredDevicesForStrategy(strategy, devices); });
+ setPreferredDevicesForStrategy(strategy, devices);
+ });
}
synchronized (mNonDefaultDevices) {
mNonDefaultDevices.forEach((strategy, devices) -> {
addDevicesRoleForStrategy(strategy, AudioSystem.DEVICE_ROLE_DISABLED,
- devices, false /* internal */); });
+ devices, false /* internal */);
+ });
}
synchronized (mPreferredDevicesForCapturePreset) {
- // TODO: call audiosystem to restore
+ mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> {
+ setDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ });
}
}
@@ -1163,6 +1174,7 @@
return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); });
purgeRoles(mAppliedPresetRolesInt, (p, r, d) -> {
return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); });
+ reapplyExternalDevicesRoles();
}
@GuardedBy("mDevicesLock")
@@ -1535,7 +1547,7 @@
}
// Reset A2DP suspend state each time a new sink is connected
- mDeviceBroker.clearA2dpSuspended();
+ mDeviceBroker.clearA2dpSuspended(true /* internalOnly */);
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
@@ -1958,7 +1970,7 @@
"LE Audio device addr=" + address + " now available").printLog(TAG));
}
// Reset LEA suspend state each time a new sink is connected
- mDeviceBroker.clearLeAudioSuspended();
+ mDeviceBroker.clearLeAudioSuspended(true /* internalOnly */);
UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index db08bea..67cb518 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -352,7 +352,6 @@
private static final int MSG_PLAY_SOUND_EFFECT = 5;
private static final int MSG_LOAD_SOUND_EFFECTS = 7;
private static final int MSG_SET_FORCE_USE = 8;
- private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
private static final int MSG_SET_ALL_VOLUMES = 10;
private static final int MSG_UNLOAD_SOUND_EFFECTS = 15;
private static final int MSG_SYSTEM_READY = 16;
@@ -1367,6 +1366,7 @@
intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
intentFilter.addAction(ACTION_CHECK_MUSIC_ACTIVE);
+ intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null,
Context.RECEIVER_EXPORTED);
@@ -3274,6 +3274,7 @@
if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
streamType = mVolumeControlStream;
} else {
+ // TODO discard activity on a muted stream?
final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
final boolean activeForReal;
if (maybeActiveStreamType == AudioSystem.STREAM_RING
@@ -3477,9 +3478,10 @@
}
} else if (isStreamMutedByRingerOrZenMode(streamTypeAlias) && streamState.mIsMuted) {
// if the stream is currently muted streams by ringer/zen mode
- // then it cannot be unmuted (without FLAG_ALLOW_RINGER_MODES)
+ // then it cannot be unmuted (without FLAG_ALLOW_RINGER_MODES) with an unmute or raise
if (direction == AudioManager.ADJUST_TOGGLE_MUTE
- || direction == AudioManager.ADJUST_UNMUTE) {
+ || direction == AudioManager.ADJUST_UNMUTE
+ || direction == AudioManager.ADJUST_RAISE) {
adjustVolume = false;
}
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index e46c3cc..c8a17e5 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -445,8 +445,8 @@
/*package*/ synchronized void resetBluetoothSco() {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- mDeviceBroker.clearA2dpSuspended();
- mDeviceBroker.clearLeAudioSuspended();
+ mDeviceBroker.clearA2dpSuspended(false /* internalOnly */);
+ mDeviceBroker.clearLeAudioSuspended(false /* internalOnly */);
mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
}
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 8ef2a1b..cb5e7f1 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -21,7 +21,10 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR_BASE;
+import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE;
+import static com.android.server.biometrics.BiometricSensor.STATE_CANCELING;
+import static com.android.server.biometrics.BiometricSensor.STATE_UNKNOWN;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
@@ -439,6 +442,13 @@
return false;
}
+ final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
+ || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+ if (errorLockout) {
+ cancelAllSensors(sensor -> Utils.isAtLeastStrength(sensorIdToStrength(sensorId),
+ sensor.getCurrentStrength()));
+ }
+
mErrorEscrow = error;
mVendorCodeEscrow = vendorCode;
@@ -477,8 +487,6 @@
case STATE_AUTH_STARTED:
case STATE_AUTH_STARTED_UI_SHOWING: {
- final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
- || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
if (isAllowDeviceCredential() && errorLockout) {
// SystemUI handles transition from biometric to device credential.
mState = STATE_SHOWING_DEVICE_CREDENTIAL;
@@ -675,7 +683,9 @@
}
private boolean pauseSensorIfSupported(int sensorId) {
- if (sensorIdToModality(sensorId) == TYPE_FACE) {
+ boolean isSensorCancelling = sensorIdToState(sensorId) == STATE_CANCELING;
+ // If the sensor is locked out, canceling sensors operation is handled in onErrorReceived()
+ if (sensorIdToModality(sensorId) == TYPE_FACE && !isSensorCancelling) {
cancelAllSensors(sensor -> sensor.id == sensorId);
return true;
}
@@ -948,6 +958,27 @@
return TYPE_NONE;
}
+ private @BiometricSensor.SensorState int sensorIdToState(int sensorId) {
+ for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
+ if (sensorId == sensor.id) {
+ return sensor.getSensorState();
+ }
+ }
+ Slog.e(TAG, "Unknown sensor: " + sensorId);
+ return STATE_UNKNOWN;
+ }
+
+ @BiometricManager.Authenticators.Types
+ private int sensorIdToStrength(int sensorId) {
+ for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
+ if (sensorId == sensor.id) {
+ return sensor.getCurrentStrength();
+ }
+ }
+ Slog.e(TAG, "Unknown sensor: " + sensorId);
+ return BIOMETRIC_CONVENIENCE;
+ }
+
private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) {
final @Modality int modality = sensorIdToModality(sensorId);
switch (modality) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
copy to services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
index 390c54e..6727fbc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerViewModule.kt
+++ b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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.
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.data
+package com.android.server.biometrics;
-import dagger.Binds
-import dagger.Module
-
-@Module
-interface BouncerViewModule {
- /** Binds BouncerView to BouncerViewImpl and makes it injectable. */
- @Binds fun bindBouncerView(bouncerViewImpl: BouncerViewImpl): BouncerView
+/**
+ * Interface for biometric operations to get camera privacy state.
+ */
+public interface BiometricSensorPrivacy {
+ /* Returns true if privacy is enabled and camera access is disabled. */
+ boolean isCameraPrivacyEnabled();
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java
new file mode 100644
index 0000000..b6701da
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.biometrics;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import android.annotation.Nullable;
+import android.hardware.SensorPrivacyManager;
+
+public class BiometricSensorPrivacyImpl implements
+ BiometricSensorPrivacy {
+ private final SensorPrivacyManager mSensorPrivacyManager;
+
+ public BiometricSensorPrivacyImpl(@Nullable SensorPrivacyManager sensorPrivacyManager) {
+ mSensorPrivacyManager = sensorPrivacyManager;
+ }
+
+ @Override
+ public boolean isCameraPrivacyEnabled() {
+ return mSensorPrivacyManager != null && mSensorPrivacyManager
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0942d85..1fa97a3 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -33,6 +33,7 @@
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
@@ -124,6 +125,8 @@
AuthSession mAuthSession;
private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final BiometricSensorPrivacy mBiometricSensorPrivacy;
+
/**
* Tracks authenticatorId invalidation. For more details, see
* {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}.
@@ -933,7 +936,7 @@
return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors,
userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */,
- getContext());
+ getContext(), mBiometricSensorPrivacy);
}
/**
@@ -1026,6 +1029,11 @@
public UserManager getUserManager(Context context) {
return context.getSystemService(UserManager.class);
}
+
+ public BiometricSensorPrivacy getBiometricSensorPrivacy(Context context) {
+ return new BiometricSensorPrivacyImpl(context.getSystemService(
+ SensorPrivacyManager.class));
+ }
}
/**
@@ -1054,6 +1062,7 @@
mRequestCounter = mInjector.getRequestGenerator();
mBiometricContext = injector.getBiometricContext(context);
mUserManager = injector.getUserManager(context);
+ mBiometricSensorPrivacy = injector.getBiometricSensorPrivacy(context);
try {
injector.getActivityManagerService().registerUserSwitchObserver(
@@ -1290,7 +1299,7 @@
final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo,
opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(),
- getContext());
+ getContext(), mBiometricSensorPrivacy);
final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
@@ -1300,9 +1309,7 @@
+ promptInfo.isIgnoreEnrollmentState());
// BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED is added so that BiometricPrompt can
// be shown for this case.
- if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS
- || preAuthStatus.second
- == BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED) {
+ if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
// If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
// CREDENTIAL is requested and available, set the bundle to only request
// CREDENTIAL.
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 3813fd1..44e3d1e 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -27,7 +27,6 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.Context;
-import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.PromptInfo;
@@ -73,13 +72,16 @@
final Context context;
private final boolean mBiometricRequested;
private final int mBiometricStrengthRequested;
+ private final BiometricSensorPrivacy mBiometricSensorPrivacy;
+
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
- Context context) {
+ Context context, BiometricSensorPrivacy biometricSensorPrivacy) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
+ mBiometricSensorPrivacy = biometricSensorPrivacy;
this.credentialRequested = credentialRequested;
this.eligibleSensors = eligibleSensors;
@@ -96,7 +98,8 @@
BiometricService.SettingObserver settingObserver,
List<BiometricSensor> sensors,
int userId, PromptInfo promptInfo, String opPackageName,
- boolean checkDevicePolicyManager, Context context)
+ boolean checkDevicePolicyManager, Context context,
+ BiometricSensorPrivacy biometricSensorPrivacy)
throws RemoteException {
final boolean confirmationRequested = promptInfo.isConfirmationRequested();
@@ -124,7 +127,7 @@
checkDevicePolicyManager, requestedStrength,
promptInfo.getAllowedSensorIds(),
promptInfo.isIgnoreEnrollmentState(),
- context);
+ biometricSensorPrivacy);
Slog.d(TAG, "Package: " + opPackageName
+ " Sensor ID: " + sensor.id
@@ -138,7 +141,7 @@
//
// Note: if only a certain sensor is required and the privacy is enabled,
// canAuthenticate() will return false.
- if (status == AUTHENTICATOR_OK || status == BIOMETRIC_SENSOR_PRIVACY_ENABLED) {
+ if (status == AUTHENTICATOR_OK) {
eligibleSensors.add(sensor);
} else {
ineligibleSensors.add(new Pair<>(sensor, status));
@@ -148,7 +151,7 @@
return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested,
- promptInfo.isIgnoreEnrollmentState(), userId, context);
+ promptInfo.isIgnoreEnrollmentState(), userId, context, biometricSensorPrivacy);
}
/**
@@ -165,7 +168,7 @@
BiometricSensor sensor, int userId, String opPackageName,
boolean checkDevicePolicyManager, int requestedStrength,
@NonNull List<Integer> requestedSensorIds,
- boolean ignoreEnrollmentState, Context context) {
+ boolean ignoreEnrollmentState, BiometricSensorPrivacy biometricSensorPrivacy) {
if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
return BIOMETRIC_NO_HARDWARE;
@@ -191,12 +194,10 @@
&& !ignoreEnrollmentState) {
return BIOMETRIC_NOT_ENROLLED;
}
- final SensorPrivacyManager sensorPrivacyManager = context
- .getSystemService(SensorPrivacyManager.class);
- if (sensorPrivacyManager != null && sensor.modality == TYPE_FACE) {
- if (sensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId)) {
+ if (biometricSensorPrivacy != null && sensor.modality == TYPE_FACE) {
+ if (biometricSensorPrivacy.isCameraPrivacyEnabled()) {
+ //Camera privacy is enabled as the access is disabled
return BIOMETRIC_SENSOR_PRIVACY_ENABLED;
}
}
@@ -292,13 +293,9 @@
@AuthenticatorStatus final int status;
@BiometricAuthenticator.Modality int modality = TYPE_NONE;
- final SensorPrivacyManager sensorPrivacyManager = context
- .getSystemService(SensorPrivacyManager.class);
-
boolean cameraPrivacyEnabled = false;
- if (sensorPrivacyManager != null) {
- cameraPrivacyEnabled = sensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, userId);
+ if (mBiometricSensorPrivacy != null) {
+ cameraPrivacyEnabled = mBiometricSensorPrivacy.isCameraPrivacyEnabled();
}
if (mBiometricRequested && credentialRequested) {
@@ -315,7 +312,7 @@
// and the face sensor privacy is enabled then return
// BIOMETRIC_SENSOR_PRIVACY_ENABLED.
//
- // Note: This sensor will still be eligible for calls to authenticate.
+ // Note: This sensor will not be eligible for calls to authenticate.
status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
} else {
status = AUTHENTICATOR_OK;
@@ -340,7 +337,7 @@
// If the only modality requested is face and the privacy is enabled
// then return BIOMETRIC_SENSOR_PRIVACY_ENABLED.
//
- // Note: This sensor will still be eligible for calls to authenticate.
+ // Note: This sensor will not be eligible for calls to authenticate.
status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
} else {
status = AUTHENTICATOR_OK;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index aa5f9fa..7fa4d6c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -573,7 +573,7 @@
final BiometricSchedulerOperation operation = mCurrentOperation;
mHandler.postDelayed(() -> {
if (operation == mCurrentOperation) {
- Counter.logIncrement("biometric.scheduler_watchdog_triggered_count");
+ Counter.logIncrement("biometric.value_scheduler_watchdog_triggered_count");
clearScheduler();
}
}, 10000);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 50d375c..7ae31b2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -212,8 +212,6 @@
// 1) Authenticated == true
// 2) Error occurred
// 3) Authenticated == false
- // 4) onLockout
- // 5) onLockoutTimed
mCallback.onClientFinished(this, true /* success */);
}
@@ -306,7 +304,11 @@
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementTimedLockoutForUser(getTargetUserId());
- onError(error, 0 /* vendorCode */);
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
}
@Override
@@ -321,6 +323,10 @@
PerformanceTracker.getInstanceForSensorId(getSensorId())
.incrementPermanentLockoutForUser(getTargetUserId());
- onError(error, 0 /* vendorCode */);
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index a501647..d6b6f77 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -475,7 +475,7 @@
BaseClientMonitor clientMonitor,
boolean success) {
mAuthSessionCoordinator.authEndedFor(userId, Utils.getCurrentStrength(sensorId),
- sensorId, requestId, client.wasAuthSuccessful());
+ sensorId, requestId, success);
}
});
});
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
index 70d7bde..984ad1d 100644
--- a/services/core/java/com/android/server/cpu/CpuInfoReader.java
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -203,15 +203,15 @@
continue;
}
if (dynamicPolicyInfo.curCpuFreqKHz == CpuInfo.MISSING_FREQUENCY
- || staticPolicyInfo.maxCpuFreqKHz == CpuInfo.MISSING_FREQUENCY) {
+ || dynamicPolicyInfo.maxCpuFreqKHz == CpuInfo.MISSING_FREQUENCY) {
Slogf.w(TAG, "Current and maximum CPU frequency information mismatch/missing for"
+ " policy ID %d", policyId);
continue;
}
- if (dynamicPolicyInfo.curCpuFreqKHz > staticPolicyInfo.maxCpuFreqKHz) {
+ if (dynamicPolicyInfo.curCpuFreqKHz > dynamicPolicyInfo.maxCpuFreqKHz) {
Slogf.w(TAG, "Current CPU frequency (%d) is greater than maximum CPU frequency"
+ " (%d) for policy ID (%d). Skipping CPU frequency policy",
- dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz, policyId);
+ dynamicPolicyInfo.curCpuFreqKHz, dynamicPolicyInfo.maxCpuFreqKHz, policyId);
continue;
}
for (int coreIdx = 0; coreIdx < staticPolicyInfo.relatedCpuCores.size(); coreIdx++) {
@@ -234,7 +234,8 @@
if (dynamicPolicyInfo.affectedCpuCores.indexOf(relatedCpuCore) < 0) {
cpuInfoByCpus.append(relatedCpuCore, new CpuInfo(relatedCpuCore,
cpusetCategories, /* isOnline= */false, CpuInfo.MISSING_FREQUENCY,
- staticPolicyInfo.maxCpuFreqKHz, CpuInfo.MISSING_FREQUENCY, usageStats));
+ dynamicPolicyInfo.maxCpuFreqKHz, CpuInfo.MISSING_FREQUENCY,
+ usageStats));
continue;
}
// If a CPU core is online, it must have the usage stats. When the usage stats is
@@ -245,7 +246,7 @@
continue;
}
CpuInfo cpuInfo = new CpuInfo(relatedCpuCore, cpusetCategories, /* isOnline= */true,
- dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz,
+ dynamicPolicyInfo.curCpuFreqKHz, dynamicPolicyInfo.maxCpuFreqKHz,
dynamicPolicyInfo.avgTimeInStateCpuFreqKHz, usageStats);
cpuInfoByCpus.append(relatedCpuCore, cpuInfo);
if (DEBUG) {
@@ -423,12 +424,6 @@
for (int i = 0; i < mCpuFreqPolicyDirsById.size(); i++) {
int policyId = mCpuFreqPolicyDirsById.keyAt(i);
File policyDir = mCpuFreqPolicyDirsById.valueAt(i);
- long maxCpuFreqKHz = readCpuFreqKHz(new File(policyDir, MAX_SCALING_FREQ_FILE));
- if (maxCpuFreqKHz == CpuInfo.MISSING_FREQUENCY) {
- Slogf.w(TAG, "Missing max CPU frequency information at %s",
- policyDir.getAbsolutePath());
- continue;
- }
File cpuCoresFile = new File(policyDir, RELATED_CPUS_FILE);
IntArray relatedCpuCores = readCpuCores(cpuCoresFile);
if (relatedCpuCores == null || relatedCpuCores.size() == 0) {
@@ -436,8 +431,7 @@
cpuCoresFile.getAbsolutePath());
continue;
}
- StaticPolicyInfo staticPolicyInfo = new StaticPolicyInfo(maxCpuFreqKHz,
- relatedCpuCores);
+ StaticPolicyInfo staticPolicyInfo = new StaticPolicyInfo(relatedCpuCores);
mStaticPolicyInfoById.append(policyId, staticPolicyInfo);
if (DEBUG) {
Slogf.d(TAG, "Added static policy info %s for policy id %d", staticPolicyInfo,
@@ -464,8 +458,14 @@
Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
continue;
}
+ long maxCpuFreqKHz = readCpuFreqKHz(new File(policyDir, MAX_SCALING_FREQ_FILE));
+ if (maxCpuFreqKHz == CpuInfo.MISSING_FREQUENCY) {
+ Slogf.w(TAG, "Missing max CPU frequency information at %s",
+ policyDir.getAbsolutePath());
+ continue;
+ }
DynamicPolicyInfo dynamicPolicyInfo = new DynamicPolicyInfo(curCpuFreqKHz,
- avgTimeInStateCpuFreqKHz, affectedCpuCores);
+ maxCpuFreqKHz, avgTimeInStateCpuFreqKHz, affectedCpuCores);
dynamicPolicyInfoById.append(policyId, dynamicPolicyInfo);
if (DEBUG) {
Slogf.d(TAG, "Read dynamic policy info %s for policy id %d", dynamicPolicyInfo,
@@ -593,9 +593,12 @@
List<String> lines = Files.readAllLines(file.toPath());
IntArray cpuCores = new IntArray(0);
for (int i = 0; i < lines.size(); i++) {
- String line = lines.get(i);
- String[] pairs = line.contains(",") ? line.trim().split(",")
- : line.trim().split(" ");
+ String line = lines.get(i).trim();
+ if (line.isEmpty()) {
+ continue;
+ }
+ String[] pairs = line.contains(",") ? line.split(",")
+ : line.split(" ");
for (int j = 0; j < pairs.length; j++) {
String[] minMaxPairs = pairs[j].split("-");
if (minMaxPairs.length >= 2) {
@@ -615,6 +618,9 @@
}
}
return cpuCores;
+ } catch (NumberFormatException e) {
+ Slogf.e(TAG, e, "Failed to read CPU cores from %s due to incorrect file format",
+ file.getAbsolutePath());
} catch (Exception e) {
Slogf.e(TAG, e, "Failed to read CPU cores from %s", file.getAbsolutePath());
}
@@ -889,29 +895,28 @@
}
private static final class StaticPolicyInfo {
- public final long maxCpuFreqKHz;
public final IntArray relatedCpuCores;
- StaticPolicyInfo(long maxCpuFreqKHz, IntArray relatedCpuCores) {
- this.maxCpuFreqKHz = maxCpuFreqKHz;
+ StaticPolicyInfo(IntArray relatedCpuCores) {
this.relatedCpuCores = relatedCpuCores;
}
@Override
public String toString() {
- return "StaticPolicyInfo{maxCpuFreqKHz = " + maxCpuFreqKHz + ", relatedCpuCores = "
- + relatedCpuCores + '}';
+ return "StaticPolicyInfo{relatedCpuCores = " + relatedCpuCores + '}';
}
}
private static final class DynamicPolicyInfo {
public final long curCpuFreqKHz;
+ public final long maxCpuFreqKHz;
public final long avgTimeInStateCpuFreqKHz;
public final IntArray affectedCpuCores;
- DynamicPolicyInfo(long curCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
+ DynamicPolicyInfo(long curCpuFreqKHz, long maxCpuFreqKHz, long avgTimeInStateCpuFreqKHz,
IntArray affectedCpuCores) {
this.curCpuFreqKHz = curCpuFreqKHz;
+ this.maxCpuFreqKHz = maxCpuFreqKHz;
this.avgTimeInStateCpuFreqKHz = avgTimeInStateCpuFreqKHz;
this.affectedCpuCores = affectedCpuCores;
}
@@ -919,6 +924,7 @@
@Override
public String toString() {
return "DynamicPolicyInfo{curCpuFreqKHz = " + curCpuFreqKHz
+ + ", maxCpuFreqKHz = " + maxCpuFreqKHz
+ ", avgTimeInStateCpuFreqKHz = " + avgTimeInStateCpuFreqKHz
+ ", affectedCpuCores = " + affectedCpuCores + '}';
}
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java
index 12813c8..47cde15 100644
--- a/services/core/java/com/android/server/display/BrightnessRangeController.java
+++ b/services/core/java/com/android/server/display/BrightnessRangeController.java
@@ -20,6 +20,7 @@
import android.os.IBinder;
import java.io.PrintWriter;
+import java.util.function.BooleanSupplier;
class BrightnessRangeController {
@@ -43,20 +44,10 @@
}
void onAmbientLuxChange(float ambientLux) {
- if (NBM_FEATURE_FLAG) {
- boolean nbmTransitionChanged = mNormalBrightnessModeController.onAmbientLuxChange(
- ambientLux);
- int previousHbm = mHbmController.getHighBrightnessMode();
- mHbmController.onAmbientLuxChange(ambientLux);
- int nextHbm = mHbmController.getHighBrightnessMode();
- // if hbm changed - callback was triggered in mHbmController.onAmbientLuxChange
- // if nbm transition not changed - no need to trigger callback
- if (previousHbm == nextHbm && nbmTransitionChanged) {
- mModeChangeCallback.run();
- }
- } else {
- mHbmController.onAmbientLuxChange(ambientLux);
- }
+ applyChanges(
+ () -> mNormalBrightnessModeController.onAmbientLuxChange(ambientLux),
+ () -> mHbmController.onAmbientLuxChange(ambientLux)
+ );
}
float getNormalBrightnessMax() {
@@ -65,10 +56,16 @@
void loadFromConfig(HighBrightnessModeMetadata hbmMetadata, IBinder token,
DisplayDeviceInfo info, DisplayDeviceConfig displayDeviceConfig) {
- mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
- mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
- displayDeviceConfig.getHighBrightnessModeData(),
- displayDeviceConfig::getHdrBrightnessFromSdr);
+ applyChanges(
+ () -> mNormalBrightnessModeController.resetNbmData(
+ displayDeviceConfig.getLuxThrottlingData()),
+ () -> {
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
+ mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
+ displayDeviceConfig.getHighBrightnessModeData(),
+ displayDeviceConfig::getHdrBrightnessFromSdr);
+ }
+ );
}
void stop() {
@@ -76,7 +73,10 @@
}
void setAutoBrightnessEnabled(int state) {
- mHbmController.setAutoBrightnessEnabled(state);
+ applyChanges(
+ () -> mNormalBrightnessModeController.setAutoBrightnessState(state),
+ () -> mHbmController.setAutoBrightnessEnabled(state)
+ );
}
void onBrightnessChanged(float brightness, float unthrottledBrightness,
@@ -109,4 +109,18 @@
float getTransitionPoint() {
return mHbmController.getTransitionPoint();
}
+
+ private void applyChanges(BooleanSupplier nbmChangesFunc, Runnable hbmChangesFunc) {
+ if (NBM_FEATURE_FLAG) {
+ boolean nbmTransitionChanged = nbmChangesFunc.getAsBoolean();
+ hbmChangesFunc.run();
+ // if nbm transition changed - trigger callback
+ // HighBrightnessModeController handles sending changes itself
+ if (nbmTransitionChanged) {
+ mModeChangeCallback.run();
+ }
+ } else {
+ hbmChangesFunc.run();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 7a797dd..7ccfb44 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -41,6 +41,7 @@
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.config.AutoBrightness;
import com.android.server.display.config.BlockingZoneConfig;
+import com.android.server.display.config.BrightnessLimitMap;
import com.android.server.display.config.BrightnessThresholds;
import com.android.server.display.config.BrightnessThrottlingMap;
import com.android.server.display.config.BrightnessThrottlingPoint;
@@ -51,8 +52,11 @@
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
import com.android.server.display.config.IntegerArray;
+import com.android.server.display.config.LuxThrottling;
import com.android.server.display.config.NitsMap;
+import com.android.server.display.config.NonNegativeFloatToFloatPoint;
import com.android.server.display.config.Point;
+import com.android.server.display.config.PredefinedBrightnessLimitNames;
import com.android.server.display.config.RefreshRateConfigs;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.RefreshRateThrottlingMap;
@@ -219,6 +223,22 @@
* <allowInLowPowerMode>false</allowInLowPowerMode>
* </highBrightnessMode>
*
+ * <luxThrottling>
+ * <brightnessLimitMap>
+ * <type>default</type>
+ * <map>
+ * <point>
+ * <first>5000</first>
+ * <second>0.3</second>
+ * </point>
+ * <point>
+ * <first>5000</first>
+ * <second>0.3</second>
+ * </point>
+ * </map>
+ * </brightnessPeakMap>
+ * </luxThrottling>
+ *
* <quirks>
* <quirk>canSetBrightnessViaHwc</quirk>
* </quirks>
@@ -693,6 +713,9 @@
private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
mRefreshRateThrottlingMap = new HashMap<>();
+ private final Map<BrightnessLimitMapType, Map<Float, Float>>
+ mLuxThrottlingData = new HashMap<>();
+
@Nullable
private HostUsiVersion mHostUsiVersion;
@@ -1344,6 +1367,11 @@
return hbmData;
}
+ @NonNull
+ public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() {
+ return mLuxThrottlingData;
+ }
+
public List<RefreshRateLimitation> getRefreshRateLimitations() {
return mRefreshRateLimitations;
}
@@ -1530,6 +1558,7 @@
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ + ", mLuxThrottlingData=" + mLuxThrottlingData
+ ", mHbmData=" + mHbmData
+ ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
+ ", mThermalBrightnessThrottlingDataMapByThrottlingId="
@@ -1676,6 +1705,7 @@
loadBrightnessMap(config);
loadThermalThrottlingConfig(config);
loadHighBrightnessModeData(config);
+ loadLuxThrottling(config);
loadQuirks(config);
loadBrightnessRamps(config);
loadAmbientLightSensorFromDdc(config);
@@ -2428,6 +2458,54 @@
}
}
+ private void loadLuxThrottling(DisplayConfiguration config) {
+ LuxThrottling cfg = config.getLuxThrottling();
+ if (cfg != null) {
+ HighBrightnessMode hbm = config.getHighBrightnessMode();
+ float hbmTransitionPoint = hbm != null ? hbm.getTransitionPoint_all().floatValue()
+ : PowerManager.BRIGHTNESS_MAX;
+ List<BrightnessLimitMap> limitMaps = cfg.getBrightnessLimitMap();
+ for (BrightnessLimitMap map : limitMaps) {
+ PredefinedBrightnessLimitNames type = map.getType();
+ BrightnessLimitMapType mappedType = BrightnessLimitMapType.convert(type);
+ if (mappedType == null) {
+ Slog.wtf(TAG, "Invalid NBM config: unsupported map type=" + type);
+ continue;
+ }
+ if (mLuxThrottlingData.containsKey(mappedType)) {
+ Slog.wtf(TAG, "Invalid NBM config: duplicate map type=" + mappedType);
+ continue;
+ }
+ Map<Float, Float> luxToTransitionPointMap = new HashMap<>();
+
+ List<NonNegativeFloatToFloatPoint> points = map.getMap().getPoint();
+ for (NonNegativeFloatToFloatPoint point : points) {
+ float lux = point.getFirst().floatValue();
+ float maxBrightness = point.getSecond().floatValue();
+ if (maxBrightness > hbmTransitionPoint) {
+ Slog.wtf(TAG,
+ "Invalid NBM config: maxBrightness is greater than hbm"
+ + ".transitionPoint. type="
+ + type + "; lux=" + lux + "; maxBrightness="
+ + maxBrightness);
+ continue;
+ }
+ if (luxToTransitionPointMap.containsKey(lux)) {
+ Slog.wtf(TAG,
+ "Invalid NBM config: duplicate lux key. type=" + type + "; lux="
+ + lux);
+ continue;
+ }
+ luxToTransitionPointMap.put(lux,
+ mBacklightToBrightnessSpline.interpolate(maxBrightness));
+ }
+ if (!luxToTransitionPointMap.isEmpty()) {
+ mLuxThrottlingData.put(mappedType, luxToTransitionPointMap);
+ }
+ }
+ }
+ }
+
private void loadBrightnessRamps(DisplayConfiguration config) {
// Priority 1: Value in the display device config (float)
// Priority 2: Value in the config.xml (int)
@@ -3155,4 +3233,19 @@
}
}
}
+
+ public enum BrightnessLimitMapType {
+ DEFAULT, ADAPTIVE;
+
+ @Nullable
+ private static BrightnessLimitMapType convert(PredefinedBrightnessLimitNames type) {
+ switch (type) {
+ case _default:
+ return DEFAULT;
+ case adaptive:
+ return ADAPTIVE;
+ }
+ return null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7d8bde9..80114cc 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2141,7 +2141,9 @@
}
void postBrightnessChangeRunnable() {
- mHandler.post(mOnBrightnessChangeRunnable);
+ if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) {
+ mHandler.post(mOnBrightnessChangeRunnable);
+ }
}
private HighBrightnessModeController createHbmControllerLocked(
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 040cecc..c8b0a72 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1788,7 +1788,9 @@
}
void postBrightnessChangeRunnable() {
- mHandler.post(mOnBrightnessChangeRunnable);
+ if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) {
+ mHandler.post(mOnBrightnessChangeRunnable);
+ }
}
private HighBrightnessModeController createHbmControllerLocked(
diff --git a/services/core/java/com/android/server/display/NormalBrightnessModeController.java b/services/core/java/com/android/server/display/NormalBrightnessModeController.java
index 91e4a9e..dbabc24 100644
--- a/services/core/java/com/android/server/display/NormalBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/NormalBrightnessModeController.java
@@ -16,36 +16,79 @@
package com.android.server.display;
+import android.annotation.NonNull;
import android.os.PowerManager;
+import com.android.server.display.DisplayDeviceConfig.BrightnessLimitMapType;
+
import java.util.HashMap;
import java.util.Map;
+/**
+ * Limits brightness for normal-brightness mode, based on ambient lux
+ **/
class NormalBrightnessModeController {
- private Map<Float, Float> mTransitionPoints = new HashMap<>();
+ @NonNull
+ private Map<BrightnessLimitMapType, Map<Float, Float>> mMaxBrightnessLimits = new HashMap<>();
+ private float mAmbientLux = Float.MAX_VALUE;
+ private boolean mAutoBrightnessEnabled = false;
// brightness limit in normal brightness mode, based on ambient lux.
- private float mVirtualTransitionPoint = PowerManager.BRIGHTNESS_MAX;
+ private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX;
boolean onAmbientLuxChange(float ambientLux) {
- float currentAmbientBoundary = Float.MAX_VALUE;
- float currentTransitionPoint = PowerManager.BRIGHTNESS_MAX;
- for (Map.Entry<Float, Float> transitionPoint: mTransitionPoints.entrySet()) {
- float ambientBoundary = transitionPoint.getKey();
- // find ambient lux upper boundary closest to current ambient lux
- if (ambientBoundary > ambientLux && ambientBoundary < currentAmbientBoundary) {
- currentTransitionPoint = transitionPoint.getValue();
- currentAmbientBoundary = ambientBoundary;
- }
- }
- if (mVirtualTransitionPoint != currentTransitionPoint) {
- mVirtualTransitionPoint = currentTransitionPoint;
- return true;
+ mAmbientLux = ambientLux;
+ return recalculateMaxBrightness();
+ }
+
+ boolean setAutoBrightnessState(int state) {
+ boolean isEnabled = state == AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
+ if (isEnabled != mAutoBrightnessEnabled) {
+ mAutoBrightnessEnabled = isEnabled;
+ return recalculateMaxBrightness();
}
return false;
}
float getCurrentBrightnessMax() {
- return mVirtualTransitionPoint;
+ return mMaxBrightness;
+ }
+
+ boolean resetNbmData(
+ @NonNull Map<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessLimits) {
+ mMaxBrightnessLimits = maxBrightnessLimits;
+ return recalculateMaxBrightness();
+ }
+
+ private boolean recalculateMaxBrightness() {
+ float foundAmbientBoundary = Float.MAX_VALUE;
+ float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX;
+
+ Map<Float, Float> maxBrightnessPoints = null;
+
+ if (mAutoBrightnessEnabled) {
+ maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.ADAPTIVE);
+ }
+
+ if (maxBrightnessPoints == null) {
+ maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.DEFAULT);
+ }
+
+ if (maxBrightnessPoints != null) {
+ for (Map.Entry<Float, Float> brightnessPoint : maxBrightnessPoints.entrySet()) {
+ float ambientBoundary = brightnessPoint.getKey();
+ // find ambient lux upper boundary closest to current ambient lux
+ if (ambientBoundary > mAmbientLux && ambientBoundary < foundAmbientBoundary) {
+ foundMaxBrightness = brightnessPoint.getValue();
+ foundAmbientBoundary = ambientBoundary;
+ }
+ }
+ }
+
+ if (mMaxBrightness != foundMaxBrightness) {
+ mMaxBrightness = foundMaxBrightness;
+ return true;
+ }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index d2dcc50..41651fd 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -126,6 +126,7 @@
private final boolean mDreamsActivatedOnChargeByDefault;
private final boolean mDreamsActivatedOnDockByDefault;
private final boolean mKeepDreamingWhenUnpluggingDefault;
+ private final boolean mDreamsDisabledByAmbientModeSuppressionConfig;
private final CopyOnWriteArrayList<DreamManagerInternal.DreamManagerStateListener>
mDreamManagerStateListeners = new CopyOnWriteArrayList<>();
@@ -239,6 +240,9 @@
mSettingsObserver = new SettingsObserver(mHandler);
mKeepDreamingWhenUnpluggingDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_keepDreamingWhenUnplugging);
+ mDreamsDisabledByAmbientModeSuppressionConfig = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig);
+
}
@Override
@@ -406,6 +410,13 @@
return false;
}
+ if (mDreamsDisabledByAmbientModeSuppressionConfig
+ && mPowerManagerInternal.isAmbientDisplaySuppressed()) {
+ // Don't dream if Bedtime (or something else) is suppressing ambient.
+ Slog.i(TAG, "Can't start dreaming because ambient is suppressed.");
+ return false;
+ }
+
if ((mWhenToDream & DREAM_ON_CHARGE) == DREAM_ON_CHARGE) {
return mIsCharging;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index da38a344..a15cb10 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -99,8 +99,7 @@
// Messages related to the physical address.
PhysicalAddressValidator physicalAddressValidator = new PhysicalAddressValidator();
addValidationInfo(Constants.MESSAGE_ACTIVE_SOURCE,
- physicalAddressValidator, ADDR_ALL ^ (ADDR_RECORDER_1 | ADDR_RECORDER_2
- | ADDR_AUDIO_SYSTEM | ADDR_RECORDER_3), ADDR_BROADCAST);
+ physicalAddressValidator, ADDR_ALL ^ ADDR_AUDIO_SYSTEM, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_INACTIVE_SOURCE,
physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java
index ff9ce6f..38a0d37 100644
--- a/services/core/java/com/android/server/input/BatteryController.java
+++ b/services/core/java/com/android/server/input/BatteryController.java
@@ -46,7 +46,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.input.BatteryController.UEventManager.UEventBatteryListener;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -102,8 +101,9 @@
@GuardedBy("mLock")
private BluetoothBatteryManager.BluetoothBatteryListener mBluetoothBatteryListener;
- BatteryController(Context context, NativeInputManagerService nativeService, Looper looper) {
- this(context, nativeService, looper, new UEventManager() {},
+ BatteryController(Context context, NativeInputManagerService nativeService, Looper looper,
+ UEventManager uEventManager) {
+ this(context, nativeService, looper, uEventManager,
new LocalBluetoothBatteryManager(context, looper));
}
@@ -567,7 +567,7 @@
private BluetoothAdapter.OnMetadataChangedListener mBluetoothMetadataListener;
@Nullable
- private UEventBatteryListener mUEventBatteryListener;
+ private BatteryController.UEventBatteryListener mUEventBatteryListener;
DeviceMonitor(int deviceId) {
mState = new State(deviceId);
@@ -630,7 +630,7 @@
return;
}
final int deviceId = mState.deviceId;
- mUEventBatteryListener = new UEventBatteryListener() {
+ mUEventBatteryListener = new BatteryController.UEventBatteryListener() {
@Override
public void onBatteryUEvent(long eventTime) {
handleUEventNotification(deviceId, eventTime);
@@ -898,40 +898,25 @@
}
}
- // An interface used to change the API of UEventObserver to a more test-friendly format.
@VisibleForTesting
- interface UEventManager {
-
- @VisibleForTesting
- abstract class UEventBatteryListener {
- private final UEventObserver mObserver = new UEventObserver() {
- @Override
- public void onUEvent(UEvent event) {
- final long eventTime = SystemClock.uptimeMillis();
- if (DEBUG) {
- Slog.d(TAG,
- "UEventListener: Received UEvent: "
- + event + " eventTime: " + eventTime);
- }
- if (!"CHANGE".equalsIgnoreCase(event.get("ACTION"))
- || !"POWER_SUPPLY".equalsIgnoreCase(event.get("SUBSYSTEM"))) {
- // Disregard any UEvents that do not correspond to battery changes.
- return;
- }
- UEventBatteryListener.this.onBatteryUEvent(eventTime);
- }
- };
-
- public abstract void onBatteryUEvent(long eventTime);
+ abstract static class UEventBatteryListener extends UEventManager.UEventListener {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ final long eventTime = SystemClock.uptimeMillis();
+ if (DEBUG) {
+ Slog.d(TAG,
+ "UEventListener: Received UEvent: "
+ + event + " eventTime: " + eventTime);
+ }
+ if (!"CHANGE".equalsIgnoreCase(event.get("ACTION"))
+ || !"POWER_SUPPLY".equalsIgnoreCase(event.get("SUBSYSTEM"))) {
+ // Disregard any UEvents that do not correspond to battery changes.
+ return;
+ }
+ UEventBatteryListener.this.onBatteryUEvent(eventTime);
}
- default void addListener(UEventBatteryListener listener, String match) {
- listener.mObserver.startObserving(match);
- }
-
- default void removeListener(UEventBatteryListener listener) {
- listener.mObserver.stopObserving();
- }
+ public abstract void onBatteryUEvent(long eventTime);
}
// An interface used to change the API of adding a bluetooth battery listener to a more
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index efe5666..ce482a9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -393,10 +393,12 @@
static class Injector {
private final Context mContext;
private final Looper mLooper;
+ private final UEventManager mUEventManager;
- Injector(Context context, Looper looper) {
+ Injector(Context context, Looper looper, UEventManager uEventManager) {
mContext = context;
mLooper = looper;
+ mUEventManager = uEventManager;
}
Context getContext() {
@@ -407,6 +409,10 @@
return mLooper;
}
+ UEventManager getUEventManager() {
+ return mUEventManager;
+ }
+
NativeInputManagerService getNativeService(InputManagerService service) {
return new NativeInputManagerService.NativeImpl(service, mLooper.getQueue());
}
@@ -417,7 +423,7 @@
}
public InputManagerService(Context context) {
- this(new Injector(context, DisplayThread.get().getLooper()));
+ this(new Injector(context, DisplayThread.get().getLooper(), new UEventManager() {}));
}
@VisibleForTesting
@@ -432,10 +438,12 @@
mSettingsObserver = new InputSettingsObserver(mContext, mHandler, this, mNative);
mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore,
injector.getLooper());
- mBatteryController = new BatteryController(mContext, mNative, injector.getLooper());
+ mBatteryController = new BatteryController(mContext, mNative, injector.getLooper(),
+ injector.getUEventManager());
mKeyboardBacklightController = InputFeatureFlagProvider.isKeyboardBacklightControlEnabled()
? new KeyboardBacklightController(mContext, mNative, mDataStore,
- injector.getLooper()) : new KeyboardBacklightControllerInterface() {};
+ injector.getLooper(), injector.getUEventManager())
+ : new KeyboardBacklightControllerInterface() {};
mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
mUseDevInputEventForAudioJack =
@@ -2553,12 +2561,17 @@
}
/**
- * Ports are highly platform-specific, so only allow these to be specified in the vendor
+ * Ports are highly platform-specific, so allow these to be specified in the odm/vendor
* directory.
*/
private static Map<String, Integer> loadStaticInputPortAssociations() {
- final File baseDir = Environment.getVendorDirectory();
- final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
+ File baseDir = Environment.getOdmDirectory();
+ File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
+
+ if (!confFile.exists()) {
+ baseDir = Environment.getVendorDirectory();
+ confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
+ }
try (final InputStream stream = new FileInputStream(confFile)) {
return ConfigurationProcessor.processInputPortAssociations(stream);
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index 1253b5b..c3205af 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -94,6 +94,7 @@
private final PersistentDataStore mDataStore;
private final Handler mHandler;
private final AnimatorFactory mAnimatorFactory;
+ private final UEventManager mUEventManager;
// Always access on handler thread or need to lock this for synchronization.
private final SparseArray<KeyboardBacklightState> mKeyboardBacklights = new SparseArray<>(1);
// Maintains state if all backlights should be on or turned off
@@ -123,19 +124,21 @@
}
KeyboardBacklightController(Context context, NativeInputManagerService nativeService,
- PersistentDataStore dataStore, Looper looper) {
- this(context, nativeService, dataStore, looper, ValueAnimator::ofInt);
+ PersistentDataStore dataStore, Looper looper, UEventManager uEventManager) {
+ this(context, nativeService, dataStore, looper, ValueAnimator::ofInt, uEventManager);
}
@VisibleForTesting
KeyboardBacklightController(Context context, NativeInputManagerService nativeService,
- PersistentDataStore dataStore, Looper looper, AnimatorFactory animatorFactory) {
+ PersistentDataStore dataStore, Looper looper, AnimatorFactory animatorFactory,
+ UEventManager uEventManager) {
mContext = context;
mNative = nativeService;
mDataStore = dataStore;
mHandler = new Handler(looper, this::handleMessage);
mAnimatorFactory = animatorFactory;
mAmbientController = new AmbientKeyboardBacklightController(context, looper);
+ mUEventManager = uEventManager;
}
@Override
@@ -152,13 +155,12 @@
// We want to observe creation of such LED nodes since they might be created after device
// FD created and InputDevice creation logic doesn't initialize LED nodes which leads to
// backlight not working.
- UEventObserver observer = new UEventObserver() {
+ mUEventManager.addListener(new UEventManager.UEventListener() {
@Override
- public void onUEvent(UEvent event) {
+ public void onUEvent(UEventObserver.UEvent event) {
onKeyboardBacklightUEvent(event);
}
- };
- observer.startObserving(UEVENT_KEYBOARD_BACKLIGHT_TAG);
+ }, UEVENT_KEYBOARD_BACKLIGHT_TAG);
if (InputFeatureFlagProvider.isAmbientKeyboardBacklightControlEnabled()) {
// Start ambient backlight controller
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 611a61a2..3ac1594 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -16,6 +16,10 @@
package com.android.server.input;
+import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE;
+import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER;
+import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -67,6 +71,8 @@
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.XmlUtils;
+import com.android.server.input.KeyboardMetricsCollector.KeyboardConfigurationEvent;
+import com.android.server.input.KeyboardMetricsCollector.LayoutSelectionCriteria;
import com.android.server.inputmethod.InputMethodManagerInternal;
import libcore.io.Streams;
@@ -118,7 +124,7 @@
// This cache stores "best-matched" layouts so that we don't need to run the matching
// algorithm repeatedly.
@GuardedBy("mKeyboardLayoutCache")
- private final Map<String, String> mKeyboardLayoutCache = new ArrayMap<>();
+ private final Map<String, KeyboardLayoutInfo> mKeyboardLayoutCache = new ArrayMap<>();
private final Object mImeInfoLock = new Object();
@Nullable
@GuardedBy("mImeInfoLock")
@@ -194,7 +200,8 @@
setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
}
}
- config.setCurrentLayout(layout);
+ config.setCurrentLayout(
+ new KeyboardLayoutInfo(layout, LAYOUT_SELECTION_CRITERIA_USER));
if (layout == null) {
// In old settings show notification always until user manually selects a
// layout in the settings.
@@ -205,18 +212,19 @@
final InputDeviceIdentifier identifier = inputDevice.getIdentifier();
final String key = getLayoutDescriptor(identifier);
Set<String> selectedLayouts = new HashSet<>();
- for (ImeInfo imeInfo : getImeInfoListForLayoutMapping()) {
+ List<ImeInfo> imeInfoList = getImeInfoListForLayoutMapping();
+ List<KeyboardLayoutInfo> layoutInfoList = new ArrayList<>();
+ boolean hasMissingLayout = false;
+ for (ImeInfo imeInfo : imeInfoList) {
// Check if the layout has been previously configured
- String layout = getKeyboardLayoutForInputDeviceInternal(identifier,
- new ImeInfo(imeInfo.mUserId, imeInfo.mImeSubtypeHandle,
- imeInfo.mImeSubtype));
- if (layout == null) {
- // If even one layout not configured properly, we need to ask user to configure
- // the keyboard properly from the Settings.
- selectedLayouts.clear();
- break;
+ KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
+ imeInfo);
+ boolean noLayoutFound = layoutInfo == null || layoutInfo.mDescriptor == null;
+ if (!noLayoutFound) {
+ selectedLayouts.add(layoutInfo.mDescriptor);
}
- selectedLayouts.add(layout);
+ layoutInfoList.add(layoutInfo);
+ hasMissingLayout |= noLayoutFound;
}
if (DEBUG) {
@@ -225,24 +233,38 @@
+ selectedLayouts);
}
+ // If even one layout not configured properly, we need to ask user to configure
+ // the keyboard properly from the Settings.
+ if (hasMissingLayout) {
+ selectedLayouts.clear();
+ }
+
config.setConfiguredLayouts(selectedLayouts);
// Update current layout: If there is a change then need to reload.
synchronized (mImeInfoLock) {
- String layout = getKeyboardLayoutForInputDeviceInternal(
+ KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
inputDevice.getIdentifier(), mCurrentImeInfo);
- if (!Objects.equals(layout, config.getCurrentLayout())) {
- config.setCurrentLayout(layout);
+ if (!Objects.equals(layoutInfo, config.getCurrentLayout())) {
+ config.setCurrentLayout(layoutInfo);
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
}
}
synchronized (mDataStore) {
try {
+ boolean isFirstConfiguration = !mDataStore.hasInputDeviceEntry(key);
if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
// Need to show the notification only if layout selection changed
// from the previous configuration
needToShowNotification = true;
+
+ // Logging keyboard configuration data to statsd only if the
+ // configuration changed from the previous configuration. Currently
+ // only logging for New Settings UI where we are using IME to decide
+ // the layout information.
+ logKeyboardConfigurationEvent(inputDevice, imeInfoList, layoutInfoList,
+ isFirstConfiguration);
}
} finally {
mDataStore.saveIfNeeded();
@@ -252,8 +274,6 @@
if (needToShowNotification) {
maybeUpdateNotification();
}
- // TODO (b/280421650): Implement logging statements using KeyboardMetricsCollector
- // for KeyboardConfigured atom
}
private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
@@ -403,7 +423,7 @@
@AnyThread
@Nullable
- public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
+ public KeyboardLayout getKeyboardLayout(@NonNull String keyboardLayoutDescriptor) {
Objects.requireNonNull(keyboardLayoutDescriptor,
"keyboardLayoutDescriptor must not be null");
@@ -751,8 +771,9 @@
String keyboardLayoutDescriptor;
if (useNewSettingsUi()) {
synchronized (mImeInfoLock) {
- keyboardLayoutDescriptor = getKeyboardLayoutForInputDeviceInternal(identifier,
+ KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
mCurrentImeInfo);
+ keyboardLayoutDescriptor = layoutInfo == null ? null : layoutInfo.mDescriptor;
}
} else {
keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
@@ -789,13 +810,13 @@
return null;
}
InputMethodSubtypeHandle subtypeHandle = InputMethodSubtypeHandle.of(imeInfo, imeSubtype);
- String layout = getKeyboardLayoutForInputDeviceInternal(identifier,
+ KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(identifier,
new ImeInfo(userId, subtypeHandle, imeSubtype));
if (DEBUG) {
Slog.d(TAG, "getKeyboardLayoutForInputDevice() " + identifier.toString() + ", userId : "
- + userId + ", subtypeHandle = " + subtypeHandle + " -> " + layout);
+ + userId + ", subtypeHandle = " + subtypeHandle + " -> " + layoutInfo);
}
- return layout;
+ return layoutInfo != null ? layoutInfo.mDescriptor : null;
}
@AnyThread
@@ -926,11 +947,11 @@
for (int i = 0; i < mConfiguredKeyboards.size(); i++) {
InputDevice inputDevice = Objects.requireNonNull(
getInputDevice(mConfiguredKeyboards.keyAt(i)));
- String layout = getKeyboardLayoutForInputDeviceInternal(inputDevice.getIdentifier(),
- mCurrentImeInfo);
+ KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
+ inputDevice.getIdentifier(), mCurrentImeInfo);
KeyboardConfiguration config = mConfiguredKeyboards.valueAt(i);
- if (!Objects.equals(layout, config.getCurrentLayout())) {
- config.setCurrentLayout(layout);
+ if (!Objects.equals(layoutInfo, config.getCurrentLayout())) {
+ config.setCurrentLayout(layoutInfo);
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
return;
}
@@ -939,39 +960,40 @@
}
@Nullable
- private String getKeyboardLayoutForInputDeviceInternal(InputDeviceIdentifier identifier,
- @Nullable ImeInfo imeInfo) {
+ private KeyboardLayoutInfo getKeyboardLayoutForInputDeviceInternal(
+ InputDeviceIdentifier identifier, @Nullable ImeInfo imeInfo) {
InputDevice inputDevice = getInputDevice(identifier);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return null;
}
String key = createLayoutKey(identifier, imeInfo);
- String layout;
synchronized (mDataStore) {
- layout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
- }
- if (layout == null) {
- synchronized (mKeyboardLayoutCache) {
- // Check Auto-selected layout cache to see if layout had been previously selected
- if (mKeyboardLayoutCache.containsKey(key)) {
- layout = mKeyboardLayoutCache.get(key);
- } else {
- // NOTE: This list is already filtered based on IME Script code
- KeyboardLayout[] layoutList = getKeyboardLayoutListForInputDeviceInternal(
- identifier, imeInfo);
- // Call auto-matching algorithm to find the best matching layout
- layout = getDefaultKeyboardLayoutBasedOnImeInfo(inputDevice, imeInfo,
- layoutList);
- mKeyboardLayoutCache.put(key, layout);
- }
+ String layout = mDataStore.getKeyboardLayout(getLayoutDescriptor(identifier), key);
+ if (layout != null) {
+ return new KeyboardLayoutInfo(layout, LAYOUT_SELECTION_CRITERIA_USER);
}
}
- return layout;
+
+ synchronized (mKeyboardLayoutCache) {
+ // Check Auto-selected layout cache to see if layout had been previously selected
+ if (mKeyboardLayoutCache.containsKey(key)) {
+ return mKeyboardLayoutCache.get(key);
+ } else {
+ // NOTE: This list is already filtered based on IME Script code
+ KeyboardLayout[] layoutList = getKeyboardLayoutListForInputDeviceInternal(
+ identifier, imeInfo);
+ // Call auto-matching algorithm to find the best matching layout
+ KeyboardLayoutInfo layoutInfo =
+ getDefaultKeyboardLayoutBasedOnImeInfo(inputDevice, imeInfo, layoutList);
+ mKeyboardLayoutCache.put(key, layoutInfo);
+ return layoutInfo;
+ }
+ }
}
@Nullable
- private static String getDefaultKeyboardLayoutBasedOnImeInfo(InputDevice inputDevice,
- @Nullable ImeInfo imeInfo, KeyboardLayout[] layoutList) {
+ private static KeyboardLayoutInfo getDefaultKeyboardLayoutBasedOnImeInfo(
+ InputDevice inputDevice, @Nullable ImeInfo imeInfo, KeyboardLayout[] layoutList) {
Arrays.sort(layoutList);
// Check <VendorID, ProductID> matching for explicitly declared custom KCM files.
@@ -984,7 +1006,8 @@
+ "vendor and product Ids. " + inputDevice.getIdentifier()
+ " : " + layout.getDescriptor());
}
- return layout.getDescriptor();
+ return new KeyboardLayoutInfo(layout.getDescriptor(),
+ LAYOUT_SELECTION_CRITERIA_DEVICE);
}
}
@@ -1001,7 +1024,7 @@
+ "HW information (Language tag and Layout type). "
+ inputDevice.getIdentifier() + " : " + layoutDesc);
}
- return layoutDesc;
+ return new KeyboardLayoutInfo(layoutDesc, LAYOUT_SELECTION_CRITERIA_DEVICE);
}
}
@@ -1023,7 +1046,10 @@
+ "IME locale matching. " + inputDevice.getIdentifier() + " : "
+ layoutDesc);
}
- return layoutDesc;
+ if (layoutDesc != null) {
+ return new KeyboardLayoutInfo(layoutDesc, LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD);
+ }
+ return null;
}
@Nullable
@@ -1229,6 +1255,26 @@
}
}
+ private void logKeyboardConfigurationEvent(@NonNull InputDevice inputDevice,
+ @NonNull List<ImeInfo> imeInfoList, @NonNull List<KeyboardLayoutInfo> layoutInfoList,
+ boolean isFirstConfiguration) {
+ if (imeInfoList.isEmpty() || layoutInfoList.isEmpty()) {
+ return;
+ }
+ KeyboardConfigurationEvent.Builder configurationEventBuilder =
+ new KeyboardConfigurationEvent.Builder(inputDevice).setIsFirstTimeConfiguration(
+ isFirstConfiguration);
+ for (int i = 0; i < imeInfoList.size(); i++) {
+ KeyboardLayoutInfo layoutInfo = layoutInfoList.get(i);
+ boolean noLayoutFound = layoutInfo == null || layoutInfo.mDescriptor == null;
+ configurationEventBuilder.addLayoutSelection(imeInfoList.get(i).mImeSubtype,
+ noLayoutFound ? null : getKeyboardLayout(layoutInfo.mDescriptor),
+ noLayoutFound ? LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+ : layoutInfo.mSelectionCriteria);
+ }
+ KeyboardMetricsCollector.logKeyboardConfiguredAtom(configurationEventBuilder.build());
+ }
+
private boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_EXISTING_DEVICES:
@@ -1411,7 +1457,7 @@
// If null, it means no layout is selected for the device.
@Nullable
- private String mCurrentLayout;
+ private KeyboardLayoutInfo mCurrentLayout;
private boolean hasConfiguredLayouts() {
return mConfiguredLayouts != null && !mConfiguredLayouts.isEmpty();
@@ -1427,15 +1473,42 @@
}
@Nullable
- private String getCurrentLayout() {
+ private KeyboardLayoutInfo getCurrentLayout() {
return mCurrentLayout;
}
- private void setCurrentLayout(String currentLayout) {
+ private void setCurrentLayout(KeyboardLayoutInfo currentLayout) {
mCurrentLayout = currentLayout;
}
}
+ private static class KeyboardLayoutInfo {
+ @Nullable
+ private final String mDescriptor;
+ @LayoutSelectionCriteria
+ private final int mSelectionCriteria;
+
+ private KeyboardLayoutInfo(@Nullable String descriptor,
+ @LayoutSelectionCriteria int selectionCriteria) {
+ mDescriptor = descriptor;
+ mSelectionCriteria = selectionCriteria;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof KeyboardLayoutInfo) {
+ return Objects.equals(mDescriptor, ((KeyboardLayoutInfo) obj).mDescriptor)
+ && mSelectionCriteria == ((KeyboardLayoutInfo) obj).mSelectionCriteria;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mSelectionCriteria + mDescriptor.hashCode();
+ }
+ }
+
private interface KeyboardLayoutVisitor {
void visitKeyboardLayout(Resources resources,
int keyboardLayoutResId, KeyboardLayout layout);
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index b8f57f5..19fa7a8 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -19,16 +19,25 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.hardware.input.KeyboardLayout;
+import android.icu.util.ULocale;
+import android.util.Log;
+import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.InputDevice;
+import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.KeyboardConfiguredProto.KeyboardLayoutConfig;
import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig;
import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Collect Keyboard metrics
@@ -36,6 +45,30 @@
public final class KeyboardMetricsCollector {
private static final String TAG = "KeyboardMetricCollector";
+ // To enable these logs, run: 'adb shell setprop log.tag.KeyboardMetricCollector DEBUG'
+ // (requires restart)
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @Retention(SOURCE)
+ @IntDef(prefix = { "LAYOUT_SELECTION_CRITERIA_" }, value = {
+ LAYOUT_SELECTION_CRITERIA_USER,
+ LAYOUT_SELECTION_CRITERIA_DEVICE,
+ LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+ })
+ public @interface LayoutSelectionCriteria {}
+
+ /** Manual selection by user */
+ public static final int LAYOUT_SELECTION_CRITERIA_USER = 0;
+
+ /** Auto-detection based on device provided language tag and layout type */
+ public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 1;
+
+ /** Auto-detection based on IME provided language tag and layout type */
+ public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 2;
+
+ @VisibleForTesting
+ static final String DEFAULT_LAYOUT = "Default";
+
/**
* Log keyboard system shortcuts for the proto
* {@link com.android.os.input.KeyboardSystemsEventReported}
@@ -43,120 +76,233 @@
*/
public static void logKeyboardSystemsEventReportedAtom(InputDevice inputDevice,
int keyboardSystemEvent, int[] keyCode, int modifierState) {
- int vendor_id = inputDevice.getVendorId();
- int product_id = inputDevice.getProductId();
+ int vendorId = inputDevice.getVendorId();
+ int productId = inputDevice.getProductId();
FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
- vendor_id, product_id, keyboardSystemEvent, keyCode, modifierState);
+ vendorId, productId, keyboardSystemEvent, keyCode, modifierState);
}
/**
* Function to log the KeyboardConfigured
* {@link com.android.os.input.KeyboardConfigured} atom
*
- * @param inputDevice Input device
- * @param keyboardLayoutConfigurations List of keyboard configurations
- * @param isFirstTimeConfiguration Whether keyboard is configured for the first time
+ * @param event {@link KeyboardConfigurationEvent} contains information about keyboard
+ * configuration. Use {@link KeyboardConfigurationEvent.Builder} to create the
+ * configuration event to log.
*/
- public static void logKeyboardConfiguredAtom(InputDevice inputDevice,
- List<KeyboardLayoutConfiguration> keyboardLayoutConfigurations,
- boolean isFirstTimeConfiguration) {
- int vendor_id = inputDevice.getVendorId();
- int product_id = inputDevice.getProductId();
-
+ public static void logKeyboardConfiguredAtom(KeyboardConfigurationEvent event) {
// Creating proto to log nested field KeyboardLayoutConfig in atom
ProtoOutputStream proto = new ProtoOutputStream();
- for (KeyboardLayoutConfiguration keyboardLayoutConfiguration :
- keyboardLayoutConfigurations) {
- addKeyboardLayoutConfigurationToProto(proto, keyboardLayoutConfiguration);
+ for (LayoutConfiguration layoutConfiguration : event.getLayoutConfigurations()) {
+ addKeyboardLayoutConfigurationToProto(proto, layoutConfiguration);
}
// Push the atom to Statsd
FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_CONFIGURED,
- isFirstTimeConfiguration, vendor_id, product_id, proto.getBytes());
+ event.isFirstConfiguration(), event.getVendorId(), event.getProductId(),
+ proto.getBytes());
+
+ if (DEBUG) {
+ Slog.d(TAG, "Logging Keyboard configuration event: " + event);
+ }
}
/**
* Populate the KeyboardLayoutConfig proto which is a repeated proto
* in the RepeatedKeyboardLayoutConfig proto with values from the
- * {@link KeyboardLayoutConfiguration} class
+ * {@link LayoutConfiguration} class
* The proto definitions can be found at:
* "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto"
*
* @param proto Representing the nested proto RepeatedKeyboardLayoutConfig
- * @param keyboardLayoutConfiguration Class containing the fields for populating the
+ * @param layoutConfiguration Class containing the fields for populating the
* KeyboardLayoutConfig proto
*/
private static void addKeyboardLayoutConfigurationToProto(ProtoOutputStream proto,
- KeyboardLayoutConfiguration keyboardLayoutConfiguration) {
+ LayoutConfiguration layoutConfiguration) {
// Start a new KeyboardLayoutConfig proto.
long keyboardLayoutConfigToken = proto.start(
RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG);
proto.write(KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG,
- keyboardLayoutConfiguration.getKeyboardLanguageTag());
+ layoutConfiguration.keyboardLanguageTag);
proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE,
- keyboardLayoutConfiguration.getKeyboardLayoutType());
+ layoutConfiguration.keyboardLayoutType);
proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME,
- keyboardLayoutConfiguration.getKeyboardLayoutName());
+ layoutConfiguration.keyboardLayoutName);
proto.write(KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA,
- keyboardLayoutConfiguration.getLayoutSelectionCriteria());
+ layoutConfiguration.layoutSelectionCriteria);
proto.end(keyboardLayoutConfigToken);
}
/**
- * Java class representing the proto KeyboardLayoutConfig defined in
- * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto"
+ * Class representing the proto KeyboardLayoutConfig defined in
+ * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto
*
* @see com.android.os.input.KeyboardConfigured
*/
- public static class KeyboardLayoutConfiguration {
- // KeyboardLayoutType in "frameworks/base/core/res/res/values/attrs.xml"
- // contains mapping for enums to int
- int mKeyboardLayoutType;
- String mKeyboardLanguageTag;
- KeyboardLayout mKeyboardLayout;
- @LayoutSelectionCriteria int mLayoutSelectionCriteria;
+ public static class KeyboardConfigurationEvent {
- @Retention(SOURCE)
- @IntDef(prefix = { "LAYOUT_SELECTION_CRITERIA_" }, value = {
- LAYOUT_SELECTION_CRITERIA_USER,
- LAYOUT_SELECTION_CRITERIA_DEVICE,
- LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
- })
- public @interface LayoutSelectionCriteria {}
+ private final InputDevice mInputDevice;
+ private final boolean mIsFirstConfiguration;
+ private final List<LayoutConfiguration> mLayoutConfigurations;
- /** Manual selection by user */
- public static final int LAYOUT_SELECTION_CRITERIA_USER = 0;
-
- /** Auto-detection based on device provided language tag and layout type */
- public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 1;
-
- /** Auto-detection based on IME provided language tag and layout type */
- public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 2;
-
- KeyboardLayoutConfiguration(int keyboardLayoutType,
- String keyboardLanguageTag,
- KeyboardLayout keyboardLayout,
- @LayoutSelectionCriteria int layoutSelectionCriteria) {
- mKeyboardLayoutType = keyboardLayoutType;
- mKeyboardLanguageTag = keyboardLanguageTag;
- mKeyboardLayout = keyboardLayout;
- mLayoutSelectionCriteria = layoutSelectionCriteria;
- }
- int getKeyboardLayoutType() {
- return mKeyboardLayoutType;
+ private KeyboardConfigurationEvent(InputDevice inputDevice, boolean isFirstConfiguration,
+ List<LayoutConfiguration> layoutConfigurations) {
+ mInputDevice = inputDevice;
+ mIsFirstConfiguration = isFirstConfiguration;
+ mLayoutConfigurations = layoutConfigurations;
}
- String getKeyboardLanguageTag() {
- return mKeyboardLanguageTag;
+ public int getVendorId() {
+ return mInputDevice.getVendorId();
}
- String getKeyboardLayoutName() {
- return mKeyboardLayout.getLabel();
+ public int getProductId() {
+ return mInputDevice.getProductId();
}
- @LayoutSelectionCriteria int getLayoutSelectionCriteria() {
- return mLayoutSelectionCriteria;
+ public boolean isFirstConfiguration() {
+ return mIsFirstConfiguration;
}
+
+ public List<LayoutConfiguration> getLayoutConfigurations() {
+ return mLayoutConfigurations;
+ }
+
+ @Override
+ public String toString() {
+ return "InputDevice = {VendorId = " + Integer.toHexString(getVendorId())
+ + ", ProductId = " + Integer.toHexString(getProductId())
+ + "}, isFirstConfiguration = " + mIsFirstConfiguration
+ + ", LayoutConfigurations = " + mLayoutConfigurations;
+ }
+
+ /**
+ * Builder class to help create {@link KeyboardConfigurationEvent}.
+ */
+ public static class Builder {
+ @NonNull
+ private final InputDevice mInputDevice;
+ private boolean mIsFirstConfiguration;
+ private final List<InputMethodSubtype> mImeSubtypeList = new ArrayList<>();
+ private final List<KeyboardLayout> mSelectedLayoutList = new ArrayList<>();
+ private final List<Integer> mLayoutSelectionCriteriaList = new ArrayList<>();
+
+ public Builder(@NonNull InputDevice inputDevice) {
+ Objects.requireNonNull(inputDevice, "InputDevice provided should not be null");
+ mInputDevice = inputDevice;
+ }
+
+ /**
+ * Set whether this is the first time this keyboard is configured.
+ */
+ public Builder setIsFirstTimeConfiguration(boolean isFirstTimeConfiguration) {
+ mIsFirstConfiguration = isFirstTimeConfiguration;
+ return this;
+ }
+
+ /**
+ * Adds keyboard layout configuration info for a particular IME subtype language
+ */
+ public Builder addLayoutSelection(@NonNull InputMethodSubtype imeSubtype,
+ @Nullable KeyboardLayout selectedLayout,
+ @LayoutSelectionCriteria int layoutSelectionCriteria) {
+ Objects.requireNonNull(imeSubtype, "IME subtype provided should not be null");
+ if (!isValidSelectionCriteria(layoutSelectionCriteria)) {
+ throw new IllegalStateException("Invalid layout selection criteria");
+ }
+ mImeSubtypeList.add(imeSubtype);
+ mSelectedLayoutList.add(selectedLayout);
+ mLayoutSelectionCriteriaList.add(layoutSelectionCriteria);
+ return this;
+ }
+
+ /**
+ * Creates {@link KeyboardConfigurationEvent} from the provided information
+ */
+ public KeyboardConfigurationEvent build() {
+ int size = mImeSubtypeList.size();
+ if (size == 0) {
+ throw new IllegalStateException("Should have at least one configuration");
+ }
+ List<LayoutConfiguration> configurationList = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ KeyboardLayout selectedLayout = mSelectedLayoutList.get(i);
+ @LayoutSelectionCriteria int layoutSelectionCriteria =
+ mLayoutSelectionCriteriaList.get(i);
+ InputMethodSubtype imeSubtype = mImeSubtypeList.get(i);
+ String keyboardLanguageTag;
+ String keyboardLayoutStringType;
+ if (layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEVICE) {
+ keyboardLanguageTag = mInputDevice.getKeyboardLanguageTag();
+ keyboardLayoutStringType = mInputDevice.getKeyboardLayoutType();
+ } else {
+ ULocale pkLocale = imeSubtype.getPhysicalKeyboardHintLanguageTag();
+ keyboardLanguageTag = pkLocale != null ? pkLocale.toLanguageTag()
+ : imeSubtype.getCanonicalizedLanguageTag();
+ keyboardLayoutStringType = imeSubtype.getPhysicalKeyboardHintLayoutType();
+ }
+ // Sanitize null values
+ String keyboardLayoutName =
+ selectedLayout == null ? DEFAULT_LAYOUT : selectedLayout.getLabel();
+ keyboardLanguageTag = keyboardLanguageTag == null ? "" : keyboardLanguageTag;
+ int keyboardLayoutType = KeyboardLayout.LayoutType.getLayoutTypeEnumValue(
+ keyboardLayoutStringType);
+
+ configurationList.add(
+ new LayoutConfiguration(keyboardLayoutType, keyboardLanguageTag,
+ keyboardLayoutName, layoutSelectionCriteria));
+ }
+ return new KeyboardConfigurationEvent(mInputDevice, mIsFirstConfiguration,
+ configurationList);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static class LayoutConfiguration {
+ // This should match enum values defined in "frameworks/base/core/res/res/values/attrs.xml"
+ public final int keyboardLayoutType;
+ public final String keyboardLanguageTag;
+ public final String keyboardLayoutName;
+ @LayoutSelectionCriteria
+ public final int layoutSelectionCriteria;
+
+ private LayoutConfiguration(int keyboardLayoutType, String keyboardLanguageTag,
+ String keyboardLayoutName, @LayoutSelectionCriteria int layoutSelectionCriteria) {
+ this.keyboardLayoutType = keyboardLayoutType;
+ this.keyboardLanguageTag = keyboardLanguageTag;
+ this.keyboardLayoutName = keyboardLayoutName;
+ this.layoutSelectionCriteria = layoutSelectionCriteria;
+ }
+
+ @Override
+ public String toString() {
+ return "{keyboardLanguageTag = " + keyboardLanguageTag + " keyboardLayoutType = "
+ + KeyboardLayout.LayoutType.getLayoutNameFromValue(keyboardLayoutType)
+ + " keyboardLayoutName = " + keyboardLayoutName + " layoutSelectionCriteria = "
+ + getStringForSelectionCriteria(layoutSelectionCriteria) + "}";
+ }
+ }
+
+ private static String getStringForSelectionCriteria(
+ @LayoutSelectionCriteria int layoutSelectionCriteria) {
+ switch (layoutSelectionCriteria) {
+ case LAYOUT_SELECTION_CRITERIA_USER:
+ return "LAYOUT_SELECTION_CRITERIA_USER";
+ case LAYOUT_SELECTION_CRITERIA_DEVICE:
+ return "LAYOUT_SELECTION_CRITERIA_DEVICE";
+ case LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD:
+ return "LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD";
+ default:
+ return "INVALID_CRITERIA";
+ }
+ }
+
+ private static boolean isValidSelectionCriteria(int layoutSelectionCriteria) {
+ return layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_USER
+ || layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEVICE
+ || layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
}
}
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index bce210d..31083fd 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -101,6 +101,10 @@
}
}
+ public boolean hasInputDeviceEntry(String inputDeviceDescriptor) {
+ return getInputDeviceState(inputDeviceDescriptor) != null;
+ }
+
public TouchCalibration getTouchCalibration(String inputDeviceDescriptor, int surfaceRotation) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
if (state == null) {
diff --git a/services/core/java/com/android/server/input/UEventManager.java b/services/core/java/com/android/server/input/UEventManager.java
new file mode 100644
index 0000000..17d87e4
--- /dev/null
+++ b/services/core/java/com/android/server/input/UEventManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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.server.input;
+
+import android.os.UEventObserver;
+
+/** An interface used to change the API of UEventObserver to a more test-friendly format. */
+interface UEventManager {
+
+ abstract class UEventListener {
+ private final UEventObserver mObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEvent event) {
+ UEventListener.this.onUEvent(event);
+ }
+ };
+
+ public abstract void onUEvent(UEventObserver.UEvent event);
+ }
+
+ default void addListener(UEventListener listener, String match) {
+ listener.mObserver.startObserving(match);
+ }
+
+ default void removeListener(UEventListener listener) {
+ listener.mObserver.stopObserving();
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 44f6900..7bb0489 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -31,7 +31,6 @@
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY;
@@ -40,8 +39,12 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
+import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
+import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;
+import static com.android.internal.widget.LockPatternUtils.pinOrPasswordQualityToCredentialType;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_STRONG;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_WEAK;
@@ -278,8 +281,6 @@
protected IGateKeeperService mGateKeeperService;
protected IAuthSecret mAuthSecretService;
- private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
-
/**
* The UIDs that are used for system credential storage in keystore.
*/
@@ -311,6 +312,7 @@
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mLockSettingsService.migrateOldDataAfterSystemReady();
mLockSettingsService.loadEscrowData();
+ mLockSettingsService.deleteRepairModePersistentDataIfNeeded();
}
}
@@ -544,7 +546,7 @@
}
public boolean isGsiRunning() {
- return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
+ return LockPatternUtils.isGsiRunning();
}
public FingerprintManager getFingerprintManager() {
@@ -952,6 +954,16 @@
return success;
}
+ @VisibleForTesting
+ void deleteRepairModePersistentDataIfNeeded() {
+ if (!LockPatternUtils.isRepairModeSupported(mContext)
+ || LockPatternUtils.isRepairModeActive(mContext)
+ || mInjector.isGsiRunning()) {
+ return;
+ }
+ mStorage.deleteRepairModePersistentData();
+ }
+
// This is called when Weaver is guaranteed to be available (if the device supports Weaver).
// It does any synthetic password related work that was delayed from earlier in the boot.
private void onThirdPartyAppsStarted() {
@@ -1282,8 +1294,8 @@
* {@link #CREDENTIAL_TYPE_PASSWORD}
*/
private int getCredentialTypeInternal(int userId) {
- if (userId == USER_FRP) {
- return getFrpCredentialType();
+ if (isSpecialUserId(userId)) {
+ return mSpManager.getSpecialUserCredentialType(userId);
}
synchronized (mSpManager) {
final long protectorId = getCurrentLskfBasedProtectorId(userId);
@@ -1299,29 +1311,6 @@
}
}
- private int getFrpCredentialType() {
- PersistentData data = mStorage.readPersistentDataBlock();
- if (data.type != PersistentData.TYPE_SP_GATEKEEPER &&
- data.type != PersistentData.TYPE_SP_WEAVER) {
- return CREDENTIAL_TYPE_NONE;
- }
- int credentialType = SyntheticPasswordManager.getFrpCredentialType(data.payload);
- if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
- return credentialType;
- }
- return pinOrPasswordQualityToCredentialType(data.qualityForUi);
- }
-
- private static int pinOrPasswordQualityToCredentialType(int quality) {
- if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
- return CREDENTIAL_TYPE_PASSWORD;
- }
- if (LockPatternUtils.isQualityNumericPin(quality)) {
- return CREDENTIAL_TYPE_PIN;
- }
- throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
- }
-
private boolean isUserSecure(int userId) {
return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
}
@@ -1563,8 +1552,8 @@
* unlock operation.
*/
private void sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId) {
- // Don't send credentials during the factory reset protection flow.
- if (userId == USER_FRP) {
+ // Don't send credentials during the special user flow.
+ if (isSpecialUserId(userId)) {
return;
}
@@ -2184,15 +2173,19 @@
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
return VerifyCredentialResponse.ERROR;
}
+ if (userId == USER_REPAIR_MODE && !LockPatternUtils.isRepairModeActive(mContext)) {
+ Slog.e(TAG, "Repair mode is not active on the device.");
+ return VerifyCredentialResponse.ERROR;
+ }
Slogf.i(TAG, "Verifying lockscreen credential for user %d", userId);
final AuthenticationResult authResult;
VerifyCredentialResponse response;
synchronized (mSpManager) {
- if (userId == USER_FRP) {
- return mSpManager.verifyFrpCredential(getGateKeeperService(), credential,
- progressCallback);
+ if (isSpecialUserId(userId)) {
+ return mSpManager.verifySpecialUserCredential(userId, getGateKeeperService(),
+ credential, progressCallback);
}
long protectorId = getCurrentLskfBasedProtectorId(userId);
@@ -2201,6 +2194,12 @@
response = authResult.gkResponse;
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ if ((flags & VERIFY_FLAG_WRITE_REPAIR_MODE_PW) != 0) {
+ if (!mSpManager.writeRepairModeCredentialLocked(protectorId, userId)) {
+ Slog.e(TAG, "Failed to write repair mode credential");
+ return VerifyCredentialResponse.ERROR;
+ }
+ }
// credential has matched
mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
authResult.syntheticPassword.deriveGkPassword());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 2fa637e..1c5ecb7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -19,7 +19,7 @@
import static android.content.Context.USER_SERVICE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
-import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
@@ -90,6 +90,9 @@
private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
+ private static final String REPAIR_MODE_DIRECTORY = "repair-mode/";
+ private static final String REPAIR_MODE_PERSISTENT_FILE = "pst";
+
private static final Object DEFAULT = new Object();
private static final String[] SETTINGS_TO_BACKUP = new String[] {
@@ -390,6 +393,29 @@
}
}
+ @VisibleForTesting
+ File getRepairModePersistentDataFile() {
+ final File directory = new File(Environment.getMetadataDirectory(), REPAIR_MODE_DIRECTORY);
+ return new File(directory, REPAIR_MODE_PERSISTENT_FILE);
+ }
+
+ public PersistentData readRepairModePersistentData() {
+ final byte[] data = readFile(getRepairModePersistentDataFile());
+ if (data == null) {
+ return PersistentData.NONE;
+ }
+ return PersistentData.fromBytes(data);
+ }
+
+ public void writeRepairModePersistentData(int persistentType, int userId, byte[] payload) {
+ writeFile(getRepairModePersistentDataFile(),
+ PersistentData.toBytes(persistentType, userId, /* qualityForUi= */0, payload));
+ }
+
+ public void deleteRepairModePersistentData() {
+ deleteFile(getRepairModePersistentDataFile());
+ }
+
/**
* Writes the synthetic password state file for the given user ID, protector ID, and state name.
* If the file already exists, then it is atomically replaced.
@@ -510,7 +536,8 @@
}
public void setString(String key, String value, int userId) {
- Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
+ Preconditions.checkArgument(!isSpecialUserId(userId),
+ "cannot store lock settings for special user: %d", userId);
writeKeyValue(key, value, userId);
if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
@@ -535,7 +562,7 @@
}
public String getString(String key, String defaultValue, int userId) {
- if (userId == USER_FRP) {
+ if (isSpecialUserId(userId)) {
return null;
}
return readKeyValue(key, defaultValue, userId);
@@ -583,6 +610,17 @@
}
}
+ /**
+ * Provides a concrete data structure to represent the minimal information from
+ * a user's LSKF-based SP protector that is needed to verify the user's LSKF,
+ * in combination with the corresponding Gatekeeper enrollment or Weaver slot.
+ * It can be stored in {@link com.android.server.PersistentDataBlockService} for
+ * FRP to live across factory resets not initiated via the Settings UI.
+ * Written to {@link #REPAIR_MODE_PERSISTENT_FILE} to support verification for
+ * exiting repair mode, since the device runs with an empty data partition in
+ * repair mode and the same credential be provided to exit repair mode is
+ * required.
+ */
public static class PersistentData {
static final byte VERSION_1 = 1;
static final int VERSION_1_HEADER_SIZE = 1 + 1 + 4 + 4;
@@ -685,6 +723,19 @@
}
pw.decreaseIndent();
}
+ // Dump repair mode file states
+ final File repairModeFile = getRepairModePersistentDataFile();
+ if (repairModeFile.exists()) {
+ pw.println(TextUtils.formatSimple("Repair Mode [%s]:", repairModeFile.getParent()));
+ pw.increaseIndent();
+ pw.println(TextUtils.formatSimple("%6d %s %s", repairModeFile.length(),
+ LockSettingsService.timestampToString(repairModeFile.lastModified()),
+ repairModeFile.getName()));
+ final PersistentData data = readRepairModePersistentData();
+ pw.println(TextUtils.formatSimple("type: %d, user id: %d, payload size: %d",
+ data.type, data.userId, data.payload != null ? data.payload.length : 0));
+ pw.decreaseIndent();
+ }
}
static class DatabaseHelper extends SQLiteOpenHelper {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index e8fd6f8..6ba7585 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -16,9 +16,14 @@
package com.android.server.locksettings;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.internal.widget.LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
+import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
+import static com.android.internal.widget.LockPatternUtils.pinOrPasswordQualityToCredentialType;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -718,11 +723,30 @@
return PasswordData.fromBytes(passwordData).credentialType;
}
- static int getFrpCredentialType(byte[] payload) {
- if (payload == null) {
+ int getSpecialUserCredentialType(int userId) {
+ final PersistentData data = getSpecialUserPersistentData(userId);
+ if (data.type != PersistentData.TYPE_SP_GATEKEEPER
+ && data.type != PersistentData.TYPE_SP_WEAVER) {
+ return CREDENTIAL_TYPE_NONE;
+ }
+ if (data.payload == null) {
return LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
- return PasswordData.fromBytes(payload).credentialType;
+ final int credentialType = PasswordData.fromBytes(data.payload).credentialType;
+ if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
+ return credentialType;
+ }
+ return pinOrPasswordQualityToCredentialType(data.qualityForUi);
+ }
+
+ private PersistentData getSpecialUserPersistentData(int userId) {
+ if (userId == USER_FRP) {
+ return mStorage.readPersistentDataBlock();
+ }
+ if (userId == USER_REPAIR_MODE) {
+ return mStorage.readRepairModePersistentData();
+ }
+ throw new IllegalArgumentException("Unknown special user id " + userId);
}
/**
@@ -1005,10 +1029,10 @@
return sizeOfCredential;
}
- public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
- LockscreenCredential userCredential,
+ public VerifyCredentialResponse verifySpecialUserCredential(int sourceUserId,
+ IGateKeeperService gatekeeper, LockscreenCredential userCredential,
ICheckCredentialProgressCallback progressCallback) {
- PersistentData persistentData = mStorage.readPersistentDataBlock();
+ final PersistentData persistentData = getSpecialUserPersistentData(sourceUserId);
if (persistentData.type == PersistentData.TYPE_SP_GATEKEEPER) {
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
byte[] stretchedLskf = stretchLskf(userCredential, pwd);
@@ -1019,13 +1043,13 @@
0 /* challenge */, pwd.passwordHandle,
stretchedLskfToGkPassword(stretchedLskf));
} catch (RemoteException e) {
- Slog.e(TAG, "FRP verifyChallenge failed", e);
+ Slog.e(TAG, "Persistent data credential verifyChallenge failed", e);
return VerifyCredentialResponse.ERROR;
}
return VerifyCredentialResponse.fromGateKeeperResponse(response);
} else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
if (!isWeaverAvailable()) {
- Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
+ Slog.e(TAG, "No weaver service to verify SP-based persistent data credential");
return VerifyCredentialResponse.ERROR;
}
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
@@ -1114,6 +1138,57 @@
}
}
+ /**
+ * Writes the user's synthetic password data to the repair mode file.
+ *
+ * @param protectorId current LSKF based protectorId
+ * @param userId user id of the user
+ */
+ public boolean writeRepairModeCredentialLocked(long protectorId, int userId) {
+ if (!shouldWriteRepairModeCredential(userId)) {
+ return false;
+ }
+ final byte[] data = loadState(PASSWORD_DATA_NAME, protectorId, userId);
+ if (data == null) {
+ Slogf.w(TAG, "Password data not found for user %d", userId);
+ return false;
+ }
+ final PasswordData pwd = PasswordData.fromBytes(data);
+ if (isNoneCredential(pwd)) {
+ Slogf.w(TAG, "User %d has NONE credential", userId);
+ return false;
+ }
+ Slogf.d(TAG, "Writing repair mode credential tied to user %d", userId);
+ final int weaverSlot = loadWeaverSlot(protectorId, userId);
+ if (weaverSlot != INVALID_WEAVER_SLOT) {
+ // write weaver password
+ mStorage.writeRepairModePersistentData(
+ PersistentData.TYPE_SP_WEAVER, weaverSlot, pwd.toBytes());
+ } else {
+ // write gatekeeper password
+ mStorage.writeRepairModePersistentData(
+ PersistentData.TYPE_SP_GATEKEEPER, userId, pwd.toBytes());
+ }
+ return true;
+ }
+
+ private boolean shouldWriteRepairModeCredential(int userId) {
+ final UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (!LockPatternUtils.canUserEnterRepairMode(mContext, userInfo)) {
+ Slogf.w(TAG, "User %d can't enter repair mode", userId);
+ return false;
+ }
+ if (LockPatternUtils.isRepairModeActive(mContext)) {
+ Slog.w(TAG, "Can't write repair mode credential while repair mode is already active");
+ return false;
+ }
+ if (LockPatternUtils.isGsiRunning()) {
+ Slog.w(TAG, "Can't write repair mode credential while GSI is running");
+ return false;
+ }
+ return true;
+ }
+
private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();
/**
@@ -1602,7 +1677,7 @@
/** Destroy all weak token-based SP protectors for the given user. */
public void destroyAllWeakTokenBasedProtectors(int userId) {
List<Long> protectorIds =
- mStorage.listSyntheticPasswordProtectorsForUser(SECDISCARDABLE_NAME, userId);
+ mStorage.listSyntheticPasswordProtectorsForUser(SP_BLOB_NAME, userId);
for (long protectorId : protectorIds) {
SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME,
protectorId, userId));
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index e5ffa7e..39b8bfd 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -34,8 +34,6 @@
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
@@ -43,15 +41,12 @@
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
import android.net.INetworkManagementEventObserver;
-import android.net.ITetheringStatsProvider;
import android.net.InetAddresses;
import android.net.InterfaceConfiguration;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.NetworkPolicyManager;
-import android.net.NetworkStack;
-import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.NetdService;
import android.os.BatteryStats;
@@ -78,28 +73,20 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.HexDump;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetdUtils.ModifyOperation;
+import com.android.net.module.util.PermissionUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.google.android.collect.Maps;
-import java.io.BufferedReader;
-import java.io.DataInputStream;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
-import java.net.InterfaceAddress;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.Objects;
/**
* @hide
@@ -129,13 +116,6 @@
private static final String TAG = "NetworkManagement";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final int MAX_UID_RANGES_PER_COMMAND = 10;
-
- static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
-
- static final boolean MODIFY_OPERATION_ADD = true;
- static final boolean MODIFY_OPERATION_REMOVE = false;
-
/**
* Binder context for this service
*/
@@ -154,10 +134,6 @@
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
new RemoteCallbackList<>();
- @GuardedBy("mTetheringStatsProviders")
- private final HashMap<ITetheringStatsProvider, String>
- mTetheringStatsProviders = Maps.newHashMap();
-
/**
* If both locks need to be held, then they should be obtained in the order:
* first {@link #mQuotaLock} and then {@link #mRulesLock}.
@@ -182,35 +158,35 @@
private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
/** Set of UIDs that are to be blocked/allowed by firewall controller. */
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallRules = new SparseIntArray();
/**
* Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
* to application idles.
*/
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
/**
* Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
* to device idles.
*/
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
/**
* Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
* to device on power-save mode.
*/
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
/**
* Contains the per-UID firewall rules that are used when Restricted Networking Mode is enabled.
*/
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray();
/**
* Contains the per-UID firewall rules that are used when Low Power Standby is enabled.
*/
@GuardedBy("mRulesLock")
- private SparseIntArray mUidFirewallLowPowerStandbyRules = new SparseIntArray();
+ private final SparseIntArray mUidFirewallLowPowerStandbyRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mRulesLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -237,17 +213,6 @@
mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
mDeps.registerLocalService(new LocalService());
-
- synchronized (mTetheringStatsProviders) {
- mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
- }
- }
-
- private NetworkManagementService() {
- mContext = null;
- mDaemonHandler = null;
- mDeps = null;
- mNetdUnsolicitedEventListener = null;
}
static NetworkManagementService create(Context context, Dependencies deps)
@@ -290,19 +255,19 @@
@Override
public void registerObserver(INetworkManagementEventObserver observer) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
mObservers.register(observer);
}
@Override
public void unregisterObserver(INetworkManagementEventObserver observer) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
mObservers.unregister(observer);
}
@FunctionalInterface
private interface NetworkManagementEventCallback {
- public void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
+ void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
}
private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
@@ -368,35 +333,6 @@
type, isActive, tsNanos, uid));
}
- @Override
- public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
- NetworkStack.checkNetworkStackPermission(mContext);
- Objects.requireNonNull(provider);
- synchronized(mTetheringStatsProviders) {
- mTetheringStatsProviders.put(provider, name);
- }
- }
-
- @Override
- public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
- NetworkStack.checkNetworkStackPermission(mContext);
- synchronized(mTetheringStatsProviders) {
- mTetheringStatsProviders.remove(provider);
- }
- }
-
- @Override
- public void tetherLimitReached(ITetheringStatsProvider provider) {
- NetworkStack.checkNetworkStackPermission(mContext);
- synchronized(mTetheringStatsProviders) {
- if (!mTetheringStatsProviders.containsKey(provider)) {
- return;
- }
- // No current code examines the interface parameter in a global alert. Just pass null.
- mDaemonHandler.post(() -> notifyLimitReached(LIMIT_GLOBAL_ALERT, null));
- }
- }
-
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
@@ -666,7 +602,7 @@
public String[] listInterfaces() {
// TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
// APIs.
- NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
try {
return mNetdService.interfaceGetList();
} catch (RemoteException | ServiceSpecificException e) {
@@ -718,7 +654,7 @@
public InterfaceConfiguration getInterfaceConfig(String iface) {
// TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
// APIs.
- NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
final InterfaceConfigurationParcel result;
try {
result = mNetdService.interfaceGetCfg(iface);
@@ -738,7 +674,7 @@
public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
// TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
// APIs.
- NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
LinkAddress linkAddr = cfg.getLinkAddress();
if (linkAddr == null || linkAddr.getAddress() == null) {
throw new IllegalStateException("Null LinkAddress given");
@@ -755,7 +691,7 @@
@Override
public void setInterfaceDown(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
ifcg.setInterfaceDown();
setInterfaceConfig(iface, ifcg);
@@ -763,7 +699,7 @@
@Override
public void setInterfaceUp(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
ifcg.setInterfaceUp();
setInterfaceConfig(iface, ifcg);
@@ -771,7 +707,7 @@
@Override
public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable);
} catch (RemoteException | ServiceSpecificException e) {
@@ -783,7 +719,7 @@
IPv6 addresses on interface down, but we need to do full clean up here */
@Override
public void clearInterfaceAddresses(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.interfaceClearAddrs(iface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -793,7 +729,7 @@
@Override
public void enableIpv6(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetEnableIPv6(iface, true);
} catch (RemoteException | ServiceSpecificException e) {
@@ -803,7 +739,7 @@
@Override
public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.setIPv6AddrGenMode(iface, mode);
} catch (RemoteException e) {
@@ -813,7 +749,7 @@
@Override
public void disableIpv6(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetEnableIPv6(iface, false);
} catch (RemoteException | ServiceSpecificException e) {
@@ -823,44 +759,16 @@
@Override
public void addRoute(int netId, RouteInfo route) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
NetdUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route);
}
@Override
public void removeRoute(int netId, RouteInfo route) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
NetdUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route);
}
- private ArrayList<String> readRouteList(String filename) {
- FileInputStream fstream = null;
- ArrayList<String> list = new ArrayList<>();
-
- try {
- fstream = new FileInputStream(filename);
- DataInputStream in = new DataInputStream(fstream);
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
- String s;
-
- // throw away the title line
-
- while (((s = br.readLine()) != null) && (s.length() != 0)) {
- list.add(s);
- }
- } catch (IOException ex) {
- // return current list, possibly empty
- } finally {
- if (fstream != null) {
- try {
- fstream.close();
- } catch (IOException ex) {}
- }
- }
-
- return list;
- }
-
@android.annotation.EnforcePermission(android.Manifest.permission.SHUTDOWN)
@Override
public void shutdown() {
@@ -873,11 +781,10 @@
@Override
public boolean getIpForwardingEnabled() throws IllegalStateException{
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
- final boolean isEnabled = mNetdService.ipfwdEnabled();
- return isEnabled;
+ return mNetdService.ipfwdEnabled();
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -885,7 +792,7 @@
@Override
public void setIpForwardingEnabled(boolean enable) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
if (enable) {
mNetdService.ipfwdEnableForwarding("tethering");
@@ -899,14 +806,9 @@
@Override
public void startTethering(String[] dhcpRange) {
- startTetheringWithConfiguration(true, dhcpRange);
- }
-
- @Override
- public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
- NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange);
+ NetdUtils.tetherStart(mNetdService, true /* usingLegacyDnsProxy */, dhcpRange);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -914,7 +816,7 @@
@Override
public void stopTethering() {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.tetherStop();
} catch (RemoteException | ServiceSpecificException e) {
@@ -924,11 +826,9 @@
@Override
public boolean isTetheringStarted() {
- NetworkStack.checkNetworkStackPermission(mContext);
-
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
- final boolean isEnabled = mNetdService.tetherIsEnabled();
- return isEnabled;
+ return mNetdService.tetherIsEnabled();
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -936,7 +836,7 @@
@Override
public void tetherInterface(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress();
final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength());
@@ -948,7 +848,7 @@
@Override
public void untetherInterface(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
NetdUtils.untetherInterface(mNetdService, iface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -958,7 +858,7 @@
@Override
public String[] listTetheredInterfaces() {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
return mNetdService.tetherInterfaceList();
} catch (RemoteException | ServiceSpecificException e) {
@@ -967,51 +867,8 @@
}
@Override
- public String[] getDnsForwarders() {
- NetworkStack.checkNetworkStackPermission(mContext);
- try {
- return mNetdService.tetherDnsList();
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
- ArrayList<InterfaceAddress> filtered = new ArrayList<>(addresses.size());
- for (InterfaceAddress ia : addresses) {
- if (!ia.getAddress().isLinkLocalAddress())
- filtered.add(ia);
- }
- return filtered;
- }
-
- private void modifyInterfaceForward(boolean add, String fromIface, String toIface) {
- try {
- if (add) {
- mNetdService.ipfwdAddInterfaceForward(fromIface, toIface);
- } else {
- mNetdService.ipfwdRemoveInterfaceForward(fromIface, toIface);
- }
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void startInterfaceForwarding(String fromIface, String toIface) {
- NetworkStack.checkNetworkStackPermission(mContext);
- modifyInterfaceForward(true, fromIface, toIface);
- }
-
- @Override
- public void stopInterfaceForwarding(String fromIface, String toIface) {
- NetworkStack.checkNetworkStackPermission(mContext);
- modifyInterfaceForward(false, fromIface, toIface);
- }
-
- @Override
public void enableNat(String internalInterface, String externalInterface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.tetherAddForward(internalInterface, externalInterface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1021,7 +878,7 @@
@Override
public void disableNat(String internalInterface, String externalInterface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.tetherRemoveForward(internalInterface, externalInterface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1031,7 +888,7 @@
@Override
public void setInterfaceQuota(String iface, long quotaBytes) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (mActiveQuotas.containsKey(iface)) {
@@ -1046,23 +903,12 @@
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
-
- synchronized (mTetheringStatsProviders) {
- for (ITetheringStatsProvider provider : mTetheringStatsProviders.keySet()) {
- try {
- provider.setInterfaceQuota(iface, quotaBytes);
- } catch (RemoteException e) {
- Log.e(TAG, "Problem setting tethering data limit on provider " +
- mTetheringStatsProviders.get(provider) + ": " + e);
- }
- }
- }
}
}
@Override
public void removeInterfaceQuota(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (!mActiveQuotas.containsKey(iface)) {
@@ -1079,23 +925,12 @@
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
-
- synchronized (mTetheringStatsProviders) {
- for (ITetheringStatsProvider provider : mTetheringStatsProviders.keySet()) {
- try {
- provider.setInterfaceQuota(iface, ITetheringStatsProvider.QUOTA_UNLIMITED);
- } catch (RemoteException e) {
- Log.e(TAG, "Problem removing tethering data limit on provider " +
- mTetheringStatsProviders.get(provider) + ": " + e);
- }
- }
- }
}
}
@Override
public void setInterfaceAlert(String iface, long alertBytes) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
// quick validity check
if (!mActiveQuotas.containsKey(iface)) {
@@ -1119,7 +954,7 @@
@Override
public void removeInterfaceAlert(String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (!mActiveAlerts.containsKey(iface)) {
@@ -1137,19 +972,8 @@
}
}
- @Override
- public void setGlobalAlert(long alertBytes) {
- NetworkStack.checkNetworkStackPermission(mContext);
-
- try {
- mNetdService.bandwidthSetGlobalAlert(alertBytes);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
private void setUidOnMeteredNetworkList(int uid, boolean allowlist, boolean enable) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
boolean oldEnable;
@@ -1261,7 +1085,7 @@
@Override
public void setUidCleartextNetworkPolicy(int uid, int policy) {
if (mDeps.getCallingUid() != uid) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
}
synchronized (mQuotaLock) {
@@ -1298,27 +1122,6 @@
return true;
}
- private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
- @Override
- public NetworkStats getTetherStats(int how) {
- // Remove the implementation of NetdTetheringStatsProvider#getTetherStats
- // since all callers are migrated to use INetd#tetherGetStats directly.
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setInterfaceQuota(String iface, long quotaBytes) {
- // Do nothing. netd is already informed of quota changes in setInterfaceQuota.
- }
- }
-
- @Override
- public NetworkStats getNetworkStatsTethering(int how) {
- // Remove the implementation of getNetworkStatsTethering since all callers are migrated
- // to use INetd#tetherGetStats directly.
- throw new UnsupportedOperationException();
- }
-
@Override
public void setFirewallEnabled(boolean enabled) {
enforceSystemUid();
@@ -1338,18 +1141,6 @@
}
@Override
- public void setFirewallInterfaceRule(String iface, boolean allow) {
- enforceSystemUid();
- Preconditions.checkState(mFirewallEnabled);
- try {
- mNetdService.firewallSetInterfaceRule(iface,
- allow ? INetd.FIREWALL_RULE_ALLOW : INetd.FIREWALL_RULE_DENY);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
synchronized (mQuotaLock) {
@@ -1619,22 +1410,9 @@
pw.println("]");
}
- private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
- NetworkStack.checkNetworkStackPermission(mContext);
- try {
- if (add) {
- mNetdService.networkAddInterface(netId, iface);
- } else {
- mNetdService.networkRemoveInterface(netId, iface);
- }
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
@Override
public void allowProtect(int uid) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.networkSetProtectAllow(uid);
@@ -1645,7 +1423,7 @@
@Override
public void denyProtect(int uid) {
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
try {
mNetdService.networkSetProtectDeny(uid);
@@ -1654,24 +1432,6 @@
}
}
- @Override
- public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
- modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface);
- // modifyInterfaceInNetwork already check calling permission.
- NetdUtils.addRoutesToLocalNetwork(mNetdService, iface, routes);
- }
-
- @Override
- public void removeInterfaceFromLocalNetwork(String iface) {
- modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, iface);
- }
-
- @Override
- public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) {
- NetworkStack.checkNetworkStackPermission(mContext);
- return NetdUtils.removeRoutesFromLocalNetwork(mNetdService, routes);
- }
-
@android.annotation.EnforcePermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
@Override
public boolean isNetworkRestricted(int uid) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8a6775..468fa6f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -119,6 +119,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -223,6 +224,8 @@
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -234,6 +237,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.VibrationEffect;
+import android.os.WorkSource;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -559,6 +563,7 @@
private PermissionHelper mPermissionHelper;
private UsageStatsManagerInternal mUsageStatsManagerInternal;
private TelecomManager mTelecomManager;
+ private PowerManager mPowerManager;
private PostNotificationTrackerFactory mPostNotificationTrackerFactory;
final IBinder mForegroundToken = new Binder();
@@ -923,7 +928,7 @@
if (oldFlags != flags) {
summary.getSbn().getNotification().flags = flags;
mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
- mPostNotificationTrackerFactory.newTracker()));
+ mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -1457,7 +1462,7 @@
// want to adjust the flag behaviour.
mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
r, true /* isAppForeground*/,
- mPostNotificationTrackerFactory.newTracker()));
+ mPostNotificationTrackerFactory.newTracker(null)));
}
}
}
@@ -1488,7 +1493,7 @@
mHandler.post(
new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
/* foreground= */ true,
- mPostNotificationTrackerFactory.newTracker()));
+ mPostNotificationTrackerFactory.newTracker(null)));
}
}
}
@@ -2233,7 +2238,7 @@
UsageStatsManagerInternal usageStatsManagerInternal,
TelecomManager telecomManager, NotificationChannelLogger channelLogger,
SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
- PermissionManager permissionManager,
+ PermissionManager permissionManager, PowerManager powerManager,
PostNotificationTrackerFactory postNotificationTrackerFactory) {
mHandler = handler;
Resources resources = getContext().getResources();
@@ -2265,6 +2270,7 @@
mDpm = dpm;
mUm = userManager;
mTelecomManager = telecomManager;
+ mPowerManager = powerManager;
mPostNotificationTrackerFactory = postNotificationTrackerFactory;
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
@@ -2338,6 +2344,7 @@
mRankingHandler,
mZenModeHelper,
mPermissionHelper,
+ mPermissionManager,
mNotificationChannelLogger,
mAppOps,
new SysUiStatsEvent.BuilderFactory(),
@@ -2568,6 +2575,7 @@
getContext().getSystemService(TelecomManager.class),
new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
getContext().getSystemService(PermissionManager.class),
+ getContext().getSystemService(PowerManager.class),
new PostNotificationTrackerFactory() {});
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
@@ -2684,7 +2692,7 @@
final boolean isAppForeground =
mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
- mPostNotificationTrackerFactory.newTracker()));
+ mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -6574,7 +6582,7 @@
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId, boolean postSilently) {
- PostNotificationTracker tracker = mPostNotificationTrackerFactory.newTracker();
+ PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
boolean enqueued = false;
try {
enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
@@ -6586,6 +6594,25 @@
}
}
+ private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) {
+ if (mFlagResolver.isEnabled(WAKE_LOCK_FOR_POSTING_NOTIFICATION)
+ && Binder.withCleanCallingIdentity(
+ () -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, false))) {
+ // The package probably doesn't have WAKE_LOCK permission and should not require it.
+ return Binder.withCleanCallingIdentity(() -> {
+ WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "NotificationManagerService:post:" + pkg);
+ wakeLock.setWorkSource(new WorkSource(uid, pkg));
+ // TODO(b/275044361): Adjust to a more reasonable number when we have the data.
+ wakeLock.acquire(30_000);
+ return mPostNotificationTrackerFactory.newTracker(wakeLock);
+ });
+ } else {
+ return mPostNotificationTrackerFactory.newTracker(null);
+ }
+ }
+
/**
* @return True if we successfully processed the notification and handed off the task of
* enqueueing it to a background thread; false otherwise.
@@ -7105,7 +7132,7 @@
mHandler.post(
new NotificationManagerService.EnqueueNotificationRunnable(
r.getUser().getIdentifier(), r, isAppForeground,
- mPostNotificationTrackerFactory.newTracker()));
+ mPostNotificationTrackerFactory.newTracker(null)));
}
}
}
@@ -12137,20 +12164,20 @@
}
interface PostNotificationTrackerFactory {
- default PostNotificationTracker newTracker() {
- return new PostNotificationTracker();
+ default PostNotificationTracker newTracker(@Nullable WakeLock optionalWakelock) {
+ return new PostNotificationTracker(optionalWakelock);
}
}
static class PostNotificationTracker {
@ElapsedRealtimeLong private final long mStartTime;
- @Nullable private NotificationRecordLogger.NotificationReported mReport;
+ @Nullable private final WakeLock mWakeLock;
private boolean mOngoing;
@VisibleForTesting
- PostNotificationTracker() {
- // TODO(b/275044361): (Conditionally) receive a wakelock.
+ PostNotificationTracker(@Nullable WakeLock wakeLock) {
mStartTime = SystemClock.elapsedRealtime();
+ mWakeLock = wakeLock;
mOngoing = true;
if (DBG) {
Slog.d(TAG, "PostNotification: Started");
@@ -12168,9 +12195,8 @@
}
/**
- * Cancels the tracker (TODO(b/275044361): releasing the acquired WakeLock). Either
- * {@link #finish} or {@link #cancel} (exclusively) should be called on this object before
- * it's discarded.
+ * Cancels the tracker (releasing the acquired WakeLock). Either {@link #finish} or
+ * {@link #cancel} (exclusively) should be called on this object before it's discarded.
*/
void cancel() {
if (!isOngoing()) {
@@ -12178,9 +12204,9 @@
return;
}
mOngoing = false;
-
- // TODO(b/275044361): Release wakelock.
-
+ if (mWakeLock != null) {
+ Binder.withCleanCallingIdentity(() -> mWakeLock.release());
+ }
if (DBG) {
long elapsedTime = SystemClock.elapsedRealtime() - mStartTime;
Slog.d(TAG, TextUtils.formatSimple("PostNotification: Abandoned after %d ms",
@@ -12189,9 +12215,9 @@
}
/**
- * Finishes the tracker (TODO(b/275044361): releasing the acquired WakeLock) and returns the
- * time elapsed since the operation started, in milliseconds. Either {@link #finish} or
- * {@link #cancel} (exclusively) should be called on this object before it's discarded.
+ * Finishes the tracker (releasing the acquired WakeLock) and returns the time elapsed since
+ * the operation started, in milliseconds. Either {@link #finish} or {@link #cancel}
+ * (exclusively) should be called on this object before it's discarded.
*/
@DurationMillisLong
long finish() {
@@ -12201,9 +12227,9 @@
return elapsedTime;
}
mOngoing = false;
-
- // TODO(b/275044361): Release wakelock.
-
+ if (mWakeLock != null) {
+ Binder.withCleanCallingIdentity(() -> mWakeLock.release());
+ }
if (DBG) {
Slog.d(TAG,
TextUtils.formatSimple("PostNotification: Finished in %d ms", elapsedTime));
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index c9a6c63..0292a99 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -27,6 +27,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.Person;
@@ -46,6 +47,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.Settings;
@@ -101,7 +103,8 @@
final int mTargetSdkVersion;
final int mOriginalFlags;
private final Context mContext;
-
+ private final KeyguardManager mKeyguardManager;
+ private final PowerManager mPowerManager;
NotificationUsageStats.SingleNotificationStats stats;
boolean isCanceled;
IBinder permissionOwner;
@@ -228,6 +231,8 @@
mUpdateTimeMs = mCreationTimeMs;
mInterruptionTimeMs = mCreationTimeMs;
mContext = context;
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
mPreChannelsNotification = isPreChannelsNotification();
@@ -1619,6 +1624,11 @@
return mPhoneNumbers;
}
+ boolean isLocked() {
+ return mKeyguardManager.isKeyguardLocked()
+ || !mPowerManager.isInteractive(); // Unlocked AOD
+ }
+
@VisibleForTesting
static final class Light {
public final int color;
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 0cc4fc4..5ca882c 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -31,9 +31,12 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.util.FrameworkStatsLog;
import java.util.ArrayList;
import java.util.Objects;
@@ -500,6 +503,8 @@
final boolean is_foreground_service;
final long timeout_millis;
final boolean is_non_dismissible;
+ final int fsi_state;
+ final boolean is_locked;
@DurationMillisLong long post_duration_millis; // Not final; calculated at the end.
NotificationReported(NotificationRecordPair p,
@@ -530,6 +535,20 @@
this.is_foreground_service = NotificationRecordLogger.isForegroundService(p.r);
this.timeout_millis = p.r.getSbn().getNotification().getTimeoutAfter();
this.is_non_dismissible = NotificationRecordLogger.isNonDismissible(p.r);
+
+ final boolean isStickyHunFlagEnabled = SystemUiSystemPropertiesFlags.getResolver()
+ .isEnabled(NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI);
+
+ final boolean hasFullScreenIntent =
+ p.r.getSbn().getNotification().fullScreenIntent != null;
+
+ final boolean hasFsiRequestedButDeniedFlag = (p.r.getSbn().getNotification().flags
+ & Notification.FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
+
+ this.fsi_state = NotificationRecordLogger.getFsiState(isStickyHunFlagEnabled,
+ hasFullScreenIntent, hasFsiRequestedButDeniedFlag, eventType);
+
+ this.is_locked = p.r.isLocked();
}
}
@@ -558,7 +577,6 @@
}
/**
- * @param r NotificationRecord
* @return Whether the notification is a non-dismissible notification.
*/
static boolean isNonDismissible(@NonNull NotificationRecord r) {
@@ -567,4 +585,28 @@
}
return (r.getNotification().flags & Notification.FLAG_NO_DISMISS) != 0;
}
+
+ /**
+ * @return FrameworkStatsLog enum of the state of the full screen intent posted with this
+ * notification.
+ */
+ static int getFsiState(boolean isStickyHunFlagEnabled,
+ boolean hasFullScreenIntent,
+ boolean hasFsiRequestedButDeniedFlag,
+ NotificationReportedEvent eventType) {
+
+ if (!isStickyHunFlagEnabled
+ || eventType == NotificationReportedEvent.NOTIFICATION_UPDATED) {
+ // Zeroes in protos take zero bandwidth, but non-zero numbers take bandwidth,
+ // so we should log 0 when possible.
+ return 0;
+ }
+ if (hasFullScreenIntent) {
+ return FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__FSI_ALLOWED;
+ }
+ if (hasFsiRequestedButDeniedFlag) {
+ return FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__FSI_DENIED;
+ }
+ return FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__NO_FSI;
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index feb75ef..9da0e98 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -75,7 +75,9 @@
notificationReported.is_foreground_service,
notificationReported.timeout_millis,
notificationReported.is_non_dismissible,
- notificationReported.post_duration_millis);
+ notificationReported.post_duration_millis,
+ notificationReported.fsi_state,
+ notificationReported.is_locked);
}
@Override
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 4399a3c..838a0fb 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -30,6 +30,9 @@
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -41,6 +44,7 @@
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -53,6 +57,7 @@
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerService;
@@ -72,6 +77,8 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -183,6 +190,7 @@
private final RankingHandler mRankingHandler;
private final ZenModeHelper mZenModeHelper;
private final PermissionHelper mPermissionHelper;
+ private final PermissionManager mPermissionManager;
private final NotificationChannelLogger mNotificationChannelLogger;
private final AppOpsManager mAppOps;
@@ -198,7 +206,7 @@
private boolean mAllowInvalidShortcuts = false;
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
- ZenModeHelper zenHelper, PermissionHelper permHelper,
+ ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
NotificationChannelLogger notificationChannelLogger,
AppOpsManager appOpsManager,
SysUiStatsEvent.BuilderFactory statsEventBuilderFactory,
@@ -207,6 +215,7 @@
mZenModeHelper = zenHelper;
mRankingHandler = rankingHandler;
mPermissionHelper = permHelper;
+ mPermissionManager = permManager;
mPm = pm;
mNotificationChannelLogger = notificationChannelLogger;
mAppOps = appOpsManager;
@@ -2027,6 +2036,43 @@
}
/**
+ * @return State of the full screen intent permission for this package.
+ */
+ @VisibleForTesting
+ int getFsiState(String pkg, int uid, boolean requestedFSIPermission, boolean isFlagEnabled) {
+ if (!isFlagEnabled) {
+ return 0;
+ }
+ if (!requestedFSIPermission) {
+ return PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
+ }
+ final AttributionSource attributionSource =
+ new AttributionSource.Builder(uid).setPackageName(pkg).build();
+
+ final int result = mPermissionManager.checkPermissionForPreflight(
+ android.Manifest.permission.USE_FULL_SCREEN_INTENT, attributionSource);
+
+ if (result == PermissionManager.PERMISSION_GRANTED) {
+ return PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
+ }
+ return PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
+ }
+
+ /**
+ * @return True if the current full screen intent permission state for this package was set by
+ * the user.
+ */
+ @VisibleForTesting
+ boolean isFsiPermissionUserSet(String pkg, int uid, int fsiState, int currentPermissionFlags,
+ boolean isStickyHunFlagEnabled) {
+ if (!isStickyHunFlagEnabled
+ || fsiState == PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED) {
+ return false;
+ }
+ return (currentPermissionFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+ }
+
+ /**
* Fills out {@link PackageNotificationPreferences} proto and wraps it in a {@link StatsEvent}.
*/
public void pullPackagePreferencesStats(List<StatsEvent> events,
@@ -2070,7 +2116,33 @@
event.writeInt(r.visibility);
event.writeInt(r.lockedAppFields);
- event.writeBoolean(importanceIsUserSet); // optional bool user_set_importance = 5;
+
+ // optional bool user_set_importance = 5;
+ event.writeBoolean(importanceIsUserSet);
+
+ // optional FsiState fsi_state = 6;
+ final boolean isStickyHunFlagEnabled = SystemUiSystemPropertiesFlags.getResolver()
+ .isEnabled(NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI);
+
+ final boolean requestedFSIPermission = mPermissionHelper.hasRequestedPermission(
+ android.Manifest.permission.USE_FULL_SCREEN_INTENT, r.pkg, r.uid);
+
+ final int fsiState = getFsiState(r.pkg, r.uid, requestedFSIPermission,
+ isStickyHunFlagEnabled);
+
+ event.writeInt(fsiState);
+
+ // optional bool is_fsi_permission_user_set = 7;
+ final int currentPermissionFlags = mPm.getPermissionFlags(
+ android.Manifest.permission.USE_FULL_SCREEN_INTENT, r.pkg,
+ UserHandle.getUserHandleForUid(r.uid));
+
+ final boolean isUserSet =
+ isFsiPermissionUserSet(r.pkg, r.uid, fsiState, currentPermissionFlags,
+ isStickyHunFlagEnabled);
+
+ event.writeBoolean(isUserSet);
+
events.add(event.build());
}
}
diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/services/core/java/com/android/server/notification/RateEstimator.java
index 19768a2..eda96ac 100644
--- a/services/core/java/com/android/server/notification/RateEstimator.java
+++ b/services/core/java/com/android/server/notification/RateEstimator.java
@@ -23,7 +23,7 @@
* {@hide}
*/
class RateEstimator {
- private static final double RATE_ALPHA = 0.5;
+ private static final double RATE_ALPHA = 0.7;
private static final double MINIMUM_DT = 0.0005;
private Long mLastEventTime;
diff --git a/services/core/java/com/android/server/notification/TEST_MAPPING b/services/core/java/com/android/server/notification/TEST_MAPPING
new file mode 100644
index 0000000..59b2bc1
--- /dev/null
+++ b/services/core/java/com/android/server/notification/TEST_MAPPING
@@ -0,0 +1,49 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsNotificationTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksUiServicesTests",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsNotificationTestCases"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index d3d1cc5..f8ee6b0 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -96,6 +96,8 @@
registerForUserRemoval();
registerForPackageRemoval();
+ BootReceiver.initDropboxRateLimiter();
+
// Scan existing tombstones.
mHandler.post(() -> {
final File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
diff --git a/services/core/java/com/android/server/pm/ArchiveManager.java b/services/core/java/com/android/server/pm/ArchiveManager.java
new file mode 100644
index 0000000..5082be6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ArchiveManager.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server.pm;
+
+import android.annotation.NonNull;
+import android.content.IntentSender;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.text.TextUtils;
+
+import com.android.server.pm.pkg.PackageStateInternal;
+
+import java.util.Objects;
+
+/**
+ * Responsible archiving apps and returning information about archived apps.
+ *
+ * <p> An archived app is in a state where the app is not fully on the device. APKs are removed
+ * while the data directory is kept. Archived apps are included in the list of launcher apps where
+ * tapping them re-installs the full app.
+ */
+final class ArchiveManager {
+
+ private final PackageManagerService mPm;
+
+ ArchiveManager(PackageManagerService mPm) {
+ this.mPm = mPm;
+ }
+
+ void archiveApp(
+ @NonNull String packageName,
+ @NonNull String callerPackageName,
+ int userId,
+ @NonNull IntentSender intentSender) throws PackageManager.NameNotFoundException {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(callerPackageName);
+ Objects.requireNonNull(intentSender);
+
+ Computer snapshot = mPm.snapshotComputer();
+ int callingUid = Binder.getCallingUid();
+ String callingPackageName = snapshot.getNameForUid(callingUid);
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "archiveApp");
+ verifyCaller(callerPackageName, callingPackageName);
+
+ PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
+ if (ps == null) {
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("Package %s not found.", packageName));
+ }
+
+ verifyInstallOwnership(packageName, callingPackageName, ps);
+
+ // TODO(b/278553670) Complete implementations
+ throw new UnsupportedOperationException("Method not implemented.");
+ }
+
+ private static void verifyCaller(String callerPackageName, String callingPackageName) {
+ if (!TextUtils.equals(callingPackageName, callerPackageName)) {
+ throw new SecurityException(
+ TextUtils.formatSimple(
+ "The callerPackageName %s set by the caller doesn't match the "
+ + "caller's own package name %s.",
+ callerPackageName,
+ callingPackageName));
+ }
+ }
+
+ private static void verifyInstallOwnership(String packageName, String callingPackageName,
+ PackageStateInternal ps) {
+ if (!TextUtils.equals(ps.getInstallSource().mInstallerPackageName,
+ callingPackageName)) {
+ throw new SecurityException(
+ TextUtils.formatSimple("Caller is not the installer of record for %s.",
+ packageName));
+ }
+ String updateOwnerPackageName = ps.getInstallSource().mUpdateOwnerPackageName;
+ if (updateOwnerPackageName != null
+ && !TextUtils.equals(updateOwnerPackageName, callingPackageName)) {
+ throw new SecurityException(
+ TextUtils.formatSimple("Caller is not the update owner for %s.", packageName));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 5f52c16..2e85c97 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -343,6 +343,20 @@
return res ? DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ /** Deletes dexopt artifacts for the given package*/
+ private void deleteArtDexoptArtifacts(String packageName) {
+ try (PackageManagerLocal.FilteredSnapshot filteredSnapshot =
+ PackageManagerServiceUtils.getPackageManagerLocal()
+ .withFilteredSnapshot()) {
+ try {
+ DexOptHelper.getArtManagerLocal().deleteDexoptArtifacts(
+ filteredSnapshot, packageName);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ Slog.w(TAG, e.toString());
+ }
+ }
+ }
+
/*
* This method handles package deletion in general
*/
@@ -484,6 +498,11 @@
action, allUserHandles, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.getPackageName());
+ if (ps.isIncremental()) {
+ // Explicitly delete dexopt artifacts for incremental app because the
+ // artifacts are not stored in the same directory as the APKs
+ deleteArtDexoptArtifacts(packageName);
+ }
deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index fa7c063..f0d5e14 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -692,7 +692,7 @@
if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
!= 0) {
permissionParamsBuilder.setAllowlistedRestrictedPermissions(
- pkgSetting.getPkg().getRequestedPermissions());
+ new ArrayList<>(pkgSetting.getPkg().getRequestedPermissions()));
}
mPm.mPermissionManager.onPackageInstalled(pkgSetting.getPkg(),
Process.INVALID_UID /* previousAppId */,
@@ -2314,9 +2314,7 @@
& PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0;
if (grantRequestedPermissions) {
var permissionStates = new ArrayMap<String, Integer>();
- var requestedPermissions = pkg.getRequestedPermissions();
- for (int index = 0; index < requestedPermissions.size(); index++) {
- var permissionName = requestedPermissions.get(index);
+ for (var permissionName : pkg.getRequestedPermissions()) {
permissionStates.put(permissionName,
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED);
}
@@ -2332,7 +2330,8 @@
(installRequest.getInstallFlags()
& PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
final List<String> allowlistedRestrictedPermissions =
- allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
+ allowlistAllRestrictedPermissions
+ ? new ArrayList<>(pkg.getRequestedPermissions())
: installRequest.getAllowlistedRestrictedPermissions();
if (allowlistedRestrictedPermissions != null) {
permissionParamsBuilder.setAllowlistedRestrictedPermissions(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c1709f8..f880c57 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7416,6 +7416,11 @@
callback);
}
+ @Nullable
+ String getDefaultBrowser(@UserIdInt int userId) {
+ return mDefaultAppProvider.getDefaultBrowser(userId);
+ }
+
void setDefaultBrowser(@Nullable String packageName, boolean async, @UserIdInt int userId) {
mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
}
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 214a8b8..9ff8392 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -557,9 +557,8 @@
serializer.startDocument(null, true);
serializer.startTag(null, TAG_DEFAULT_APPS);
- synchronized (mPm.mLock) {
- mPm.mSettings.writeDefaultAppsLPr(serializer, userId);
- }
+ final String defaultBrowser = mPm.getDefaultBrowser(userId);
+ Settings.writeDefaultApps(serializer, defaultBrowser);
serializer.endTag(null, TAG_DEFAULT_APPS);
serializer.endDocument();
@@ -584,12 +583,7 @@
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
(parser1, userId1) -> {
- final String defaultBrowser;
- synchronized (mPm.mLock) {
- mPm.mSettings.readDefaultAppsLPw(parser1, userId1);
- defaultBrowser = mPm.mSettings.removeDefaultBrowserPackageNameLPw(
- userId1);
- }
+ final String defaultBrowser = Settings.readDefaultApps(parser1);
if (defaultBrowser != null) {
mPm.setDefaultBrowser(defaultBrowser, false, userId1);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4477119..be03125 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1691,6 +1691,19 @@
void readDefaultAppsLPw(XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
+ String defaultBrowser = readDefaultApps(parser);
+ if (defaultBrowser != null) {
+ mDefaultBrowserApp.put(userId, defaultBrowser);
+ }
+ }
+
+ /**
+ * @return the package name for the default browser app, or {@code null} if none.
+ */
+ @Nullable
+ static String readDefaultApps(@NonNull XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String defaultBrowser = null;
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1700,8 +1713,7 @@
}
String tagName = parser.getName();
if (tagName.equals(TAG_DEFAULT_BROWSER)) {
- String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- mDefaultBrowserApp.put(userId, packageName);
+ defaultBrowser = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
} else if (tagName.equals(TAG_DEFAULT_DIALER)) {
// Ignored.
} else {
@@ -1711,6 +1723,7 @@
XmlUtils.skipCurrentTag(parser);
}
}
+ return defaultBrowser;
}
void readBlockUninstallPackagesLPw(TypedXmlPullParser parser, int userId)
@@ -2085,8 +2098,13 @@
void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(null, TAG_DEFAULT_APPS);
String defaultBrowser = mDefaultBrowserApp.get(userId);
+ writeDefaultApps(serializer, defaultBrowser);
+ }
+
+ static void writeDefaultApps(@NonNull XmlSerializer serializer, @Nullable String defaultBrowser)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_DEFAULT_APPS);
if (!TextUtils.isEmpty(defaultBrowser)) {
serializer.startTag(null, TAG_DEFAULT_BROWSER);
serializer.attribute(null, ATTR_PACKAGE_NAME, defaultBrowser);
@@ -3724,11 +3742,16 @@
if (parser.getName().equals(TAG_PERMISSIONS)) {
final LegacyPermissionState legacyState;
if (ps.hasSharedUser()) {
- legacyState = getSettingLPr(ps.getSharedUserAppId()).getLegacyPermissionState();
+ final SettingBase sharedUserSettings = getSettingLPr(
+ ps.getSharedUserAppId());
+ legacyState = sharedUserSettings != null
+ ? sharedUserSettings.getLegacyPermissionState() : null;
} else {
legacyState = ps.getLegacyPermissionState();
}
- readInstallPermissionsLPr(parser, legacyState, users);
+ if (legacyState != null) {
+ readInstallPermissionsLPr(parser, legacyState, users);
+ }
} else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
readUsesStaticLibLPw(parser, ps);
} else if (parser.getName().equals(TAG_USES_SDK_LIB)) {
@@ -4998,10 +5021,9 @@
if ((permissionNames != null || dumpAll) && pkg != null
&& pkg.getRequestedPermissions() != null
&& pkg.getRequestedPermissions().size() > 0) {
- final List<String> perms = pkg.getRequestedPermissions();
+ final Set<String> perms = pkg.getRequestedPermissions();
pw.print(prefix); pw.println(" requested permissions:");
- for (int i=0; i<perms.size(); i++) {
- String perm = perms.get(i);
+ for (String perm : perms) {
if (permissionNames != null
&& !permissionNames.contains(perm)) {
continue;
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 00f7dc4..bac300d 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -23,7 +23,6 @@
import android.content.pm.UserPackage;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -32,8 +31,6 @@
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.pm.ShortcutService.DumpFilter;
-import libcore.io.IoUtils;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -41,7 +38,6 @@
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -264,45 +260,41 @@
public static ShortcutLauncher loadFromFile(File path, ShortcutUser shortcutUser,
int ownerUserId, boolean fromBackup) {
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
+ if (in == null) {
+ Slog.d(TAG, "Not found " + path);
+ return null;
+ }
- final AtomicFile file = new AtomicFile(path);
- final FileInputStream in;
- try {
- in = file.openRead();
- } catch (FileNotFoundException e) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Not found " + path);
+ ShortcutLauncher ret = null;
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+
+ final String tag = parser.getName();
+ if (ShortcutService.DEBUG_LOAD) {
+ Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
+ }
+ if ((depth == 1) && TAG_ROOT.equals(tag)) {
+ ret = loadFromXml(parser, shortcutUser, ownerUserId, fromBackup);
+ continue;
+ }
+ ShortcutService.throwForInvalidTag(depth, tag);
+ }
+ return ret;
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+ file.failRead(in, e);
+ return loadFromFile(path, shortcutUser, ownerUserId, fromBackup);
}
- return null;
- }
-
- try {
- ShortcutLauncher ret = null;
- TypedXmlPullParser parser = Xml.resolvePullParser(in);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
-
- final String tag = parser.getName();
- if (ShortcutService.DEBUG_LOAD) {
- Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
- }
- if ((depth == 1) && TAG_ROOT.equals(tag)) {
- ret = loadFromXml(parser, shortcutUser, ownerUserId, fromBackup);
- continue;
- }
- ShortcutService.throwForInvalidTag(depth, tag);
- }
- return ret;
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
- return null;
- } finally {
- IoUtils.closeQuietly(in);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 28cb7f0..0ea45c4 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -50,7 +50,6 @@
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -69,8 +68,6 @@
import com.android.server.pm.ShortcutService.ShortcutOperation;
import com.android.server.pm.ShortcutService.Stats;
-import libcore.io.IoUtils;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -78,7 +75,6 @@
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1969,45 +1965,41 @@
public static ShortcutPackage loadFromFile(ShortcutService s, ShortcutUser shortcutUser,
File path, boolean fromBackup) {
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
+ if (in == null) {
+ Slog.d(TAG, "Not found " + path);
+ return null;
+ }
- final AtomicFile file = new AtomicFile(path);
- final FileInputStream in;
- try {
- in = file.openRead();
- } catch (FileNotFoundException e) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Not found " + path);
+ ShortcutPackage ret = null;
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+
+ final String tag = parser.getName();
+ if (ShortcutService.DEBUG_LOAD || ShortcutService.DEBUG_REBOOT) {
+ Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
+ }
+ if ((depth == 1) && TAG_ROOT.equals(tag)) {
+ ret = loadFromXml(s, shortcutUser, parser, fromBackup);
+ continue;
+ }
+ ShortcutService.throwForInvalidTag(depth, tag);
+ }
+ return ret;
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
+ file.failRead(in, e);
+ return loadFromFile(s, shortcutUser, path, fromBackup);
}
- return null;
- }
-
- try {
- ShortcutPackage ret = null;
- TypedXmlPullParser parser = Xml.resolvePullParser(in);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final int depth = parser.getDepth();
-
- final String tag = parser.getName();
- if (ShortcutService.DEBUG_LOAD || ShortcutService.DEBUG_REBOOT) {
- Slog.d(TAG, String.format("depth=%d type=%d name=%s", depth, type, tag));
- }
- if ((depth == 1) && TAG_ROOT.equals(tag)) {
- ret = loadFromXml(s, shortcutUser, parser, fromBackup);
- continue;
- }
- ShortcutService.throwForInvalidTag(depth, tag);
- }
- return ret;
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
- return null;
- } finally {
- IoUtils.closeQuietly(in);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 8b118da..8667888 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -20,14 +20,13 @@
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
-import android.util.AtomicFile;
+import android.os.FileUtils;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlSerializer;
-import com.android.server.security.FileIntegrity;
import org.json.JSONException;
import org.json.JSONObject;
@@ -160,36 +159,31 @@
@GuardedBy("mLock")
public void saveToFileLocked(File path, boolean forBackup) {
- final AtomicFile file = new AtomicFile(path);
- FileOutputStream os = null;
- try {
- os = file.startWrite();
-
- // Write to XML
- final TypedXmlSerializer itemOut;
- if (forBackup) {
- itemOut = Xml.newFastSerializer();
- itemOut.setOutput(os, StandardCharsets.UTF_8.name());
- } else {
- itemOut = Xml.resolveSerializer(os);
- }
- itemOut.startDocument(null, true);
-
- saveToXml(itemOut, forBackup);
-
- itemOut.endDocument();
-
- os.flush();
- file.finishWrite(os);
-
+ try (ResilientAtomicFile file = getResilientFile(path)) {
+ FileOutputStream os = null;
try {
- FileIntegrity.setUpFsVerity(path);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to verity-protect " + path, e);
+ os = file.startWrite();
+
+ // Write to XML
+ final TypedXmlSerializer itemOut;
+ if (forBackup) {
+ itemOut = Xml.newFastSerializer();
+ itemOut.setOutput(os, StandardCharsets.UTF_8.name());
+ } else {
+ itemOut = Xml.resolveSerializer(os);
+ }
+ itemOut.startDocument(null, true);
+
+ saveToXml(itemOut, forBackup);
+
+ itemOut.endDocument();
+
+ os.flush();
+ file.finishWrite(os);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+ file.failWrite(os);
}
- } catch (XmlPullParserException | IOException e) {
- Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
- file.failWrite(os);
}
}
@@ -265,9 +259,18 @@
void removeShortcutPackageItem() {
synchronized (mLock) {
- getShortcutPackageItemFile().delete();
+ getResilientFile(getShortcutPackageItemFile()).delete();
}
}
protected abstract File getShortcutPackageItemFile();
+
+ protected static ResilientAtomicFile getResilientFile(File file) {
+ String path = file.getPath();
+ File temporaryBackup = new File(path + ".backup");
+ File reserveCopy = new File(path + ".reservecopy");
+ int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH;
+ return new ResilientAtomicFile(file, temporaryBackup, reserveCopy, fileMode,
+ "shortcut package item", null);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a020728..5b3514c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2547,10 +2547,7 @@
enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
"getShareTargets");
final ComponentName chooser = injectChooserActivity();
- final String pkg = (chooser != null
- && mPackageManagerInternal.getComponentEnabledSetting(chooser,
- injectBinderCallingUid(), userId) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
- ? chooser.getPackageName() : mContext.getPackageName();
+ final String pkg = chooser != null ? chooser.getPackageName() : mContext.getPackageName();
synchronized (mLock) {
throwIfUserLockedL(userId);
final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 94eb6bb..d32eb22 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -437,14 +437,14 @@
} else {
final File root = s.injectUserDataPath(userId);
- forAllFilesIn(new File(root, DIRECTORY_PACKAGES), (File f) -> {
+ forMainFilesIn(new File(root, DIRECTORY_PACKAGES), (File f) -> {
final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
if (sp != null) {
ret.mPackages.put(sp.getPackageName(), sp);
}
});
- forAllFilesIn(new File(root, DIRECTORY_LUANCHERS), (File f) -> {
+ forMainFilesIn(new File(root, DIRECTORY_LUANCHERS), (File f) -> {
final ShortcutLauncher sl =
ShortcutLauncher.loadFromFile(f, ret, userId, fromBackup);
if (sl != null) {
@@ -456,13 +456,15 @@
return ret;
}
- private static void forAllFilesIn(File path, Consumer<File> callback) {
+ private static void forMainFilesIn(File path, Consumer<File> callback) {
if (!path.exists()) {
return;
}
File[] list = path.listFiles();
for (File f : list) {
- callback.accept(f);
+ if (!f.getName().endsWith(".reservecopy") && !f.getName().endsWith(".backup")) {
+ callback.accept(f);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index f036835..9d7354e 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -160,8 +160,8 @@
*/
@NonNull
@Deprecated
- @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class)
- protected List<String> requestedPermissions = emptyList();
+ @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
+ protected Set<String> requestedPermissions = emptySet();
@NonNull
@DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class)
protected List<String> protectedBroadcasts = emptyList();
@@ -277,8 +277,8 @@
@NonNull
private List<ParsedUsesPermission> usesPermissions = emptyList();
@NonNull
- @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringList.class)
- private List<String> implicitPermissions = emptyList();
+ @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
+ private Set<String> implicitPermissions = emptySet();
@NonNull
private Set<String> upgradeKeySets = emptySet();
@NonNull
@@ -967,7 +967,7 @@
@NonNull
@Override
- public List<String> getImplicitPermissions() {
+ public Set<String> getImplicitPermissions() {
return implicitPermissions;
}
@@ -1225,7 +1225,7 @@
@NonNull
@Override
@Deprecated
- public List<String> getRequestedPermissions() {
+ public Set<String> getRequestedPermissions() {
return requestedPermissions;
}
@@ -2729,7 +2729,7 @@
usesOptionalNativeLibraries = Collections.unmodifiableList(usesOptionalNativeLibraries);
originalPackages = Collections.unmodifiableList(originalPackages);
adoptPermissions = Collections.unmodifiableList(adoptPermissions);
- requestedPermissions = Collections.unmodifiableList(requestedPermissions);
+ requestedPermissions = Collections.unmodifiableSet(requestedPermissions);
protectedBroadcasts = Collections.unmodifiableList(protectedBroadcasts);
apexSystemServices = Collections.unmodifiableList(apexSystemServices);
@@ -2750,7 +2750,7 @@
featureGroups = Collections.unmodifiableList(featureGroups);
usesPermissions = Collections.unmodifiableList(usesPermissions);
usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries);
- implicitPermissions = Collections.unmodifiableList(implicitPermissions);
+ implicitPermissions = Collections.unmodifiableSet(implicitPermissions);
upgradeKeySets = Collections.unmodifiableSet(upgradeKeySets);
keySetMapping = Collections.unmodifiableMap(keySetMapping);
attributions = Collections.unmodifiableList(attributions);
@@ -3121,9 +3121,9 @@
dest.writeByteArray(this.restrictUpdateHash);
dest.writeStringList(this.originalPackages);
sForInternedStringList.parcel(this.adoptPermissions, dest, flags);
- sForInternedStringList.parcel(this.requestedPermissions, dest, flags);
+ sForInternedStringSet.parcel(this.requestedPermissions, dest, flags);
ParsingUtils.writeParcelableList(dest, this.usesPermissions);
- sForInternedStringList.parcel(this.implicitPermissions, dest, flags);
+ sForInternedStringSet.parcel(this.implicitPermissions, dest, flags);
sForStringSet.parcel(this.upgradeKeySets, dest, flags);
ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping);
sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags);
@@ -3273,10 +3273,10 @@
this.restrictUpdateHash = in.createByteArray();
this.originalPackages = in.createStringArrayList();
this.adoptPermissions = sForInternedStringList.unparcel(in);
- this.requestedPermissions = sForInternedStringList.unparcel(in);
+ this.requestedPermissions = sForInternedStringSet.unparcel(in);
this.usesPermissions = ParsingUtils.createTypedInterfaceList(in,
ParsedUsesPermissionImpl.CREATOR);
- this.implicitPermissions = sForInternedStringList.unparcel(in);
+ this.implicitPermissions = sForInternedStringSet.unparcel(in);
this.upgradeKeySets = sForStringSet.unparcel(in);
this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in);
this.protectedBroadcasts = sForInternedStringList.unparcel(in);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 30afb0b..dbe2d54 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -156,10 +156,13 @@
LocalServices.addService(PermissionManagerServiceInternal.class, localService);
LocalServices.addService(PermissionManagerInternal.class, localService);
- mPermissionManagerServiceImpl = new PermissionManagerServiceImpl(context,
- availableFeatures);
- //mPermissionManagerServiceImpl = new PermissionManagerServiceLoggingDecorator(
- // LocalServices.getService(PermissionManagerServiceInterface.class));
+ if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
+ mPermissionManagerServiceImpl = LocalServices.getService(
+ PermissionManagerServiceInterface.class);
+ } else {
+ mPermissionManagerServiceImpl = new PermissionManagerServiceImpl(context,
+ availableFeatures);
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index a299b56..20abfe6 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -140,6 +140,7 @@
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ParsedPermission;
import com.android.server.pm.pkg.component.ParsedPermissionGroup;
@@ -1118,9 +1119,7 @@
ArrayList<String> allowlistedPermissions = null;
- final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
- for (int i = 0; i < permissionCount; i++) {
- final String permissionName = pkg.getRequestedPermissions().get(i);
+ for (final String permissionName : pkg.getRequestedPermissions()) {
final int currentFlags =
uidState.getPermissionFlags(permissionName);
if ((currentFlags & queryFlags) != 0) {
@@ -1747,10 +1746,7 @@
| FLAG_PERMISSION_POLICY_FIXED;
final String packageName = pkg.getPackageName();
- final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
- for (int i = 0; i < permissionCount; i++) {
- final String permName = pkg.getRequestedPermissions().get(i);
-
+ for (final String permName : pkg.getRequestedPermissions()) {
final boolean isRuntimePermission;
synchronized (mLock) {
final Permission permission = mRegistry.getPermission(permName);
@@ -2046,11 +2042,9 @@
final int callingUid = Binder.getCallingUid();
for (int userId: getAllUserIds()) {
- int numRequestedPermissions = newPackage.getRequestedPermissions().size();
- for (int i = 0; i < numRequestedPermissions; i++) {
- PermissionInfo permInfo = getPermissionInfo(
- newPackage.getRequestedPermissions().get(i),
- 0, newPackage.getPackageName());
+ for (final String permName : newPackage.getRequestedPermissions()) {
+ PermissionInfo permInfo = getPermissionInfo(permName, 0,
+ newPackage.getPackageName());
if (permInfo == null) {
continue;
}
@@ -2382,10 +2376,8 @@
if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
}
- n = pkg.getRequestedPermissions().size();
r = null;
- for (int i = 0; i < n; i++) {
- final String permissionName = pkg.getRequestedPermissions().get(i);
+ for (final String permissionName : pkg.getRequestedPermissions()) {
final Permission permission = mRegistry.getPermission(permissionName);
if (permission != null && permission.isAppOp()) {
mRegistry.removeAppOpPermissionPackage(permissionName,
@@ -2503,11 +2495,8 @@
ArraySet<String> shouldGrantSignaturePermission = null;
ArraySet<String> shouldGrantInternalPermission = null;
ArraySet<String> shouldGrantPrivilegedPermissionIfWasGranted = new ArraySet<>();
- final List<String> requestedPermissions = pkg.getRequestedPermissions();
- final int requestedPermissionsSize = requestedPermissions.size();
- for (int i = 0; i < requestedPermissionsSize; i++) {
- final String permissionName = pkg.getRequestedPermissions().get(i);
-
+ final Set<String> requestedPermissions = pkg.getRequestedPermissions();
+ for (final String permissionName : pkg.getRequestedPermissions()) {
final Permission permission;
synchronized (mLock) {
permission = mRegistry.getPermission(permissionName);
@@ -2638,9 +2627,7 @@
ArraySet<String> newImplicitPermissions = new ArraySet<>();
final String friendlyName = pkg.getPackageName() + "(" + pkg.getUid() + ")";
- for (int i = 0; i < requestedPermissionsSize; i++) {
- final String permName = requestedPermissions.get(i);
-
+ for (final String permName : requestedPermissions) {
final Permission bp = mRegistry.getPermission(permName);
final boolean appSupportsRuntimePermissions =
pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
@@ -2833,7 +2820,9 @@
} else if (!permissionPolicyInitialized
|| (!hardRestricted || restrictionExempt)) {
if ((origPermState != null && origPermState.isGranted())) {
- uidState.grantPermission(bp);
+ if (!uidState.grantPermission(bp)) {
+ wasChanged = true;
+ }
}
}
if (mIsLeanback && NOTIFICATION_PERMISSIONS.contains(permName)) {
@@ -3634,12 +3623,9 @@
@UserIdInt int userId) {
ArraySet<String> oldGrantedRestrictedPermissions = null;
boolean updatePermissions = false;
- final int permissionCount = pkg.getRequestedPermissions().size();
final int myUid = Process.myUid();
- for (int j = 0; j < permissionCount; j++) {
- final String permissionName = pkg.getRequestedPermissions().get(j);
-
+ for (final String permissionName : pkg.getRequestedPermissions()) {
final boolean isGranted;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permissionName);
@@ -4446,8 +4432,13 @@
final int appId = ps.getAppId();
final LegacyPermissionState legacyState;
if (ps.hasSharedUser()) {
- legacyState = mPackageManagerInt.getSharedUserApi(
- ps.getSharedUserAppId()).getSharedUserLegacyPermissionState();
+ final int sharedUserId = ps.getSharedUserAppId();
+ SharedUserApi sharedUserApi = mPackageManagerInt.getSharedUserApi(sharedUserId);
+ if (sharedUserApi == null) {
+ Slog.wtf(TAG, "Missing shared user Api for " + sharedUserId);
+ return;
+ }
+ legacyState = sharedUserApi.getSharedUserLegacyPermissionState();
} else {
legacyState = ps.getLegacyPermissionState();
}
@@ -4492,8 +4483,13 @@
ps.setInstallPermissionsFixed(false);
final LegacyPermissionState legacyState;
if (ps.hasSharedUser()) {
- legacyState = mPackageManagerInt.getSharedUserApi(
- ps.getSharedUserAppId()).getSharedUserLegacyPermissionState();
+ final int sharedUserId = ps.getSharedUserAppId();
+ SharedUserApi sharedUserApi = mPackageManagerInt.getSharedUserApi(sharedUserId);
+ if (sharedUserApi == null) {
+ Slog.wtf(TAG, "Missing shared user Api for " + sharedUserId);
+ return;
+ }
+ legacyState = sharedUserApi.getSharedUserLegacyPermissionState();
} else {
legacyState = ps.getLegacyPermissionState();
}
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index e54f34d..91854fd 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -775,7 +775,7 @@
* @hide
*/
@NonNull
- List<String> getImplicitPermissions();
+ Set<String> getImplicitPermissions();
/**
* @see ApplicationInfo#installLocation
@@ -1123,7 +1123,7 @@
* @hide
*/
@NonNull
- List<String> getRequestedPermissions();
+ Set<String> getRequestedPermissions();
/**
* Whether or not the app requested explicitly resizeable Activities. Null value means nothing
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 7fc3356..f1f0fa3 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -456,7 +456,7 @@
List<ParsedActivity> getReceivers();
@NonNull
- List<String> getRequestedPermissions();
+ Set<String> getRequestedPermissions();
@Nullable
Boolean getResizeableActivity();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 1567af0..e2cb87e 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2958,7 +2958,7 @@
final int listSize = mSplitPermissionInfos.size();
for (int is = 0; is < listSize; is++) {
final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is);
- List<String> requestedPermissions = pkg.getRequestedPermissions();
+ Set<String> requestedPermissions = pkg.getRequestedPermissions();
if (pkg.getTargetSdkVersion() >= spi.getTargetSdk()
|| !requestedPermissions.contains(spi.getSplitPermission())) {
continue;
diff --git a/services/core/java/com/android/server/policy/OWNERS b/services/core/java/com/android/server/policy/OWNERS
index 8887e40..f20ea4b 100644
--- a/services/core/java/com/android/server/policy/OWNERS
+++ b/services/core/java/com/android/server/policy/OWNERS
@@ -1,3 +1,6 @@
include /services/core/java/com/android/server/wm/OWNERS
include /services/core/java/com/android/server/input/OWNERS
-include /services/core/java/com/android/server/pm/permission/OWNERS
+per-file *AppOp* = file:/services/core/java/com/android/server/pm/permission/OWNERS
+per-file *Permission* = file:/services/core/java/com/android/server/pm/permission/OWNERS
+per-file OWNERS = file:/services/core/java/com/android/server/pm/permission/OWNERS
+per-file TEST_MAPPING = file:/services/core/java/com/android/server/pm/permission/OWNERS
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 7cbc297..2679fce 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -583,6 +583,10 @@
}
private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) {
+ if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
+ return;
+ }
+
if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")");
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f86d68a..a075655 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -602,8 +602,8 @@
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
- // Whether to lock the device after the next app transition has finished.
- boolean mLockAfterAppTransitionFinished;
+ // Whether to lock the device after the next dreaming transition has finished.
+ private boolean mLockAfterDreamingTransitionFinished;
// Allowed theater mode wake actions
private boolean mAllowTheaterModeWakeFromKey;
@@ -826,7 +826,6 @@
@Override public void onChange(boolean selfChange) {
updateSettings();
- updateRotation(false);
}
}
@@ -1106,7 +1105,7 @@
synchronized (mLock) {
// If the setting to lock instantly on power button press is true, then set the flag to
// lock after the dream transition has finished.
- mLockAfterAppTransitionFinished =
+ mLockAfterDreamingTransitionFinished =
mLockPatternUtils.getPowerButtonInstantlyLocks(mCurrentUserId);
}
@@ -2298,20 +2297,22 @@
true /* notifyOccluded */);
synchronized (mLock) {
- mLockAfterAppTransitionFinished = false;
+ mLockAfterDreamingTransitionFinished = false;
}
}
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
synchronized (mLock) {
- if (!mLockAfterAppTransitionFinished) {
- return;
+ final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
+ // check both isDreaming and mLockAfterDreamingTransitionFinished before lockNow
+ // so it won't relock after dreaming has stopped
+ if (dreamManagerInternal != null && dreamManagerInternal.isDreaming()
+ && mLockAfterDreamingTransitionFinished) {
+ lockNow(null);
}
- mLockAfterAppTransitionFinished = false;
+ mLockAfterDreamingTransitionFinished = false;
}
-
- lockNow(null);
}
});
@@ -3083,6 +3084,12 @@
return key_consumed;
}
break;
+ case KeyEvent.KEYCODE_L:
+ if (down && event.isMetaPressed() && repeatCount == 0) {
+ lockNow(null /* options */);
+ return key_consumed;
+ }
+ break;
case KeyEvent.KEYCODE_N:
if (down && event.isMetaPressed()) {
if (event.isCtrlPressed()) {
diff --git a/services/core/java/com/android/server/policy/role/OWNERS b/services/core/java/com/android/server/policy/role/OWNERS
new file mode 100644
index 0000000..a462da8
--- /dev/null
+++ b/services/core/java/com/android/server/policy/role/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/permission/OWNERS
diff --git a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
index f45bda7..6cc4258 100644
--- a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
+++ b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
@@ -57,7 +57,6 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -314,11 +313,10 @@
dataOutputStream.writeInt(packageManagerInternal.getApplicationEnabledState(
pkg.getPackageName(), userId));
- final List<String> requestedPermissions = pkg.getRequestedPermissions();
- final int requestedPermissionsSize = requestedPermissions.size();
- dataOutputStream.writeInt(requestedPermissionsSize);
- for (int i = 0; i < requestedPermissionsSize; i++) {
- dataOutputStream.writeUTF(requestedPermissions.get(i));
+ final Set<String> requestedPermissions = pkg.getRequestedPermissions();
+ dataOutputStream.writeInt(requestedPermissions.size());
+ for (String permissionName : requestedPermissions) {
+ dataOutputStream.writeUTF(permissionName);
}
final ArraySet<String> enabledComponents =
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3caeeae..fc971e4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -283,7 +283,7 @@
private static final long ENHANCED_DISCHARGE_PREDICTION_BROADCAST_MIN_DELAY_MS = 60 * 1000L;
/**
- * Apps targeting Android U and above need to define
+ * Apps targeting Android V and above need to define
* {@link android.Manifest.permission#TURN_SCREEN_ON} in their manifest for
* {@link android.os.PowerManager#ACQUIRE_CAUSES_WAKEUP} to have any effect.
* Note that most applications should use {@link android.R.attr#turnScreenOn} or
@@ -291,7 +291,7 @@
* previous foreground app from being resumed first when the screen turns on.
*/
@ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
public static final long REQUIRE_TURN_SCREEN_ON_PERMISSION = 216114297L;
/** Reason ID for holding display suspend blocker. */
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 43f96e7..99064bc 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -589,6 +589,8 @@
@Override
public int onCommand(String cmd) {
switch(cmd != null ? cmd : "") {
+ case "inject-temperature":
+ return runInjectTemperature();
case "override-status":
return runOverrideStatus();
case "reset":
@@ -611,6 +613,95 @@
}
}
+
+ private int runInjectTemperature() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final PrintWriter pw = getOutPrintWriter();
+ int type;
+ String typeName = getNextArgRequired();
+ switch (typeName.toUpperCase()) {
+ case "UNKNOWN":
+ type = Temperature.TYPE_UNKNOWN;
+ break;
+ case "CPU":
+ type = Temperature.TYPE_CPU;
+ break;
+ case "GPU":
+ type = Temperature.TYPE_GPU;
+ break;
+ case "BATTERY":
+ type = Temperature.TYPE_BATTERY;
+ break;
+ case "SKIN":
+ type = Temperature.TYPE_SKIN;
+ break;
+ case "USB_PORT":
+ type = Temperature.TYPE_USB_PORT;
+ break;
+ case "POWER_AMPLIFIER":
+ type = Temperature.TYPE_POWER_AMPLIFIER;
+ break;
+ case "BCL_VOLTAGE":
+ type = Temperature.TYPE_BCL_VOLTAGE;
+ break;
+ case "BCL_CURRENT":
+ type = Temperature.TYPE_BCL_CURRENT;
+ break;
+ case "BCL_PERCENTAGE":
+ type = Temperature.TYPE_BCL_PERCENTAGE;
+ break;
+ case "NPU":
+ type = Temperature.TYPE_NPU;
+ break;
+ default:
+ pw.println("Invalid temperature type: " + typeName);
+ return -1;
+ }
+ int throttle;
+ String throttleName = getNextArgRequired();
+ switch (throttleName.toUpperCase()) {
+ case "NONE":
+ throttle = Temperature.THROTTLING_NONE;
+ break;
+ case "LIGHT":
+ throttle = Temperature.THROTTLING_LIGHT;
+ break;
+ case "MODERATE":
+ throttle = Temperature.THROTTLING_MODERATE;
+ break;
+ case "SEVERE":
+ throttle = Temperature.THROTTLING_SEVERE;
+ break;
+ case "CRITICAL":
+ throttle = Temperature.THROTTLING_CRITICAL;
+ break;
+ case "EMERGENCY":
+ throttle = Temperature.THROTTLING_EMERGENCY;
+ break;
+ case "SHUTDOWN":
+ throttle = Temperature.THROTTLING_SHUTDOWN;
+ break;
+ default:
+ pw.println("Invalid throttle status: " + throttleName);
+ return -1;
+ }
+ String name = getNextArgRequired();
+ float value = 28.0f;
+ try {
+ String valueStr = getNextArg();
+ if (valueStr != null) value = Float.parseFloat(valueStr);
+ } catch (RuntimeException ex) {
+ pw.println("Error: " + ex.toString());
+ return -1;
+ }
+ onTemperatureChanged(new Temperature(value, type, name, throttle), true);
+ return 0;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private int runOverrideStatus() {
final long token = Binder.clearCallingIdentity();
try {
@@ -643,6 +734,9 @@
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
+ pw.println(" inject-temperature TYPE STATUS NAME [VALUE]");
+ pw.println(" injects a new temperature sample for the specified device.");
+ pw.println(" type and status strings follow the names in android.os.Temperature.");
pw.println(" override-status STATUS");
pw.println(" sets and locks the thermal status of the device to STATUS.");
pw.println(" status code is defined in android.os.Temperature.");
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index b4613a7..efb3622 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -171,7 +171,7 @@
true, /* disableAod */
true, /* disableLaunchBoost */
true, /* disableOptionalSensors */
- true, /* disableVibration */
+ false, /* disableVibration */
false, /* enableAdjustBrightness */
false, /* enableDataSaver */
true, /* enableFirewall */
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 301e612..8e37527 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -82,6 +82,11 @@
private Set<Integer> mUsingDemuxHandles = new HashSet<>();
/**
+ * Client id sharee that has shared frontend with the current client.
+ */
+ private Integer mShareeFeClientId = INVALID_RESOURCE_ID;
+
+ /**
* List of the Lnb handles that are used by the current client.
*/
private Set<Integer> mUsingLnbHandles = new HashSet<>();
@@ -225,12 +230,21 @@
return mShareFeClientIds;
}
+ public Integer getShareeFeClientId() {
+ return mShareeFeClientId;
+ }
+
+ public void setShareeFeClientId(Integer shareeFeClientId) {
+ mShareeFeClientId = shareeFeClientId;
+ }
+
/**
* Called when the client released a frontend.
*/
public void releaseFrontend() {
mUsingFrontendHandles.clear();
mShareFeClientIds.clear();
+ mShareeFeClientId = INVALID_RESOURCE_ID;
mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 8f41608..c526016 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -1087,9 +1087,15 @@
if (DEBUG) {
Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId);
}
+ Integer shareeFeClientId = getClientProfile(selfClientId).getShareeFeClientId();
+ if (shareeFeClientId != ClientProfile.INVALID_RESOURCE_ID) {
+ getClientProfile(shareeFeClientId).stopSharingFrontend(selfClientId);
+ getClientProfile(selfClientId).releaseFrontend();
+ }
for (int feId : getClientProfile(targetClientId).getInUseFrontendHandles()) {
getClientProfile(selfClientId).useFrontend(feId);
}
+ getClientProfile(selfClientId).setShareeFeClientId(targetClientId);
getClientProfile(targetClientId).shareFrontend(selfClientId);
}
@@ -1099,6 +1105,8 @@
// change the owner of all the inUse frontend
newOwnerProfile.shareFrontend(currentOwnerId);
currentOwnerProfile.stopSharingFrontend(newOwnerId);
+ newOwnerProfile.setShareeFeClientId(ClientProfile.INVALID_RESOURCE_ID);
+ currentOwnerProfile.setShareeFeClientId(newOwnerId);
for (int inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
getFrontendResource(inUseHandle).setOwner(newOwnerId);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index 9ff6a0d..d87fca4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -133,16 +133,14 @@
*/
final Rect cropHint = new Rect(0, 0, 0, 0);
- WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) {
- this.userId = userId;
- wallpaperFile = new File(wallpaperDir, inputFileName);
- cropFile = new File(wallpaperDir, cropFileName);
- }
-
WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) {
- this(userId, getWallpaperDir(userId),
- (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
- (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ this.userId = userId;
+ this.mWhich = wallpaperType;
+ File wallpaperDir = getWallpaperDir(userId);
+ String wallpaperFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER;
+ String cropFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP;
+ this.wallpaperFile = new File(wallpaperDir, wallpaperFileName);
+ this.cropFile = new File(wallpaperDir, cropFileName);
}
/**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6e43690..1e9abd9 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -371,6 +371,7 @@
if (lockedWallpaper != null) {
detachWallpaperLocked(lockedWallpaper);
}
+ clearWallpaperBitmaps(mWallpaper.userId, FLAG_LOCK);
mLockWallpaperMap.remove(wallpaper.userId);
notifyColorsWhich |= FLAG_LOCK;
}
@@ -1462,6 +1463,10 @@
}
}
+ synchronized (mLock) {
+ saveSettingsLocked(mNewWallpaper.userId);
+ }
+
if (DEBUG) {
Slog.v(TAG, "--- wallpaper changed --");
Slog.v(TAG, "new sysWp: " + mWallpaperMap.get(mCurrentUserId));
@@ -2032,7 +2037,11 @@
WallpaperData data = null;
synchronized (mLock) {
- clearWallpaperLocked(false, which, userId, null);
+ if (mIsLockscreenLiveWallpaperEnabled) {
+ clearWallpaperLocked(callingPackage, false, which, userId);
+ } else {
+ clearWallpaperLocked(false, which, userId, null);
+ }
if (which == FLAG_LOCK) {
data = mLockWallpaperMap.get(userId);
@@ -2049,7 +2058,64 @@
}
}
- void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
+ private void clearWallpaperLocked(String callingPackage, boolean defaultFailed,
+ int which, int userId) {
+
+ // Might need to bring it in the first time to establish our rewrite
+ if (!mWallpaperMap.contains(userId)) {
+ loadSettingsLocked(userId, false, FLAG_LOCK | FLAG_SYSTEM);
+ }
+ final WallpaperData wallpaper = mWallpaperMap.get(userId);
+ final WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
+ if (which == FLAG_LOCK && lockWallpaper == null) {
+ // It's already gone; we're done.
+ if (DEBUG) {
+ Slog.i(TAG, "Lock wallpaper already cleared");
+ }
+ return;
+ }
+
+ RuntimeException e = null;
+ try {
+ if (userId != mCurrentUserId && !hasCrossUserPermission()) return;
+
+ final ComponentName component;
+ final int finalWhich;
+
+ if ((which & FLAG_LOCK) > 0 && lockWallpaper != null) {
+ clearWallpaperBitmaps(lockWallpaper);
+ }
+ if ((which & FLAG_SYSTEM) > 0) {
+ clearWallpaperBitmaps(wallpaper);
+ }
+
+ // lock only case: set the system wallpaper component to both screens
+ if (which == FLAG_LOCK) {
+ component = wallpaper.wallpaperComponent;
+ finalWhich = FLAG_LOCK | FLAG_SYSTEM;
+ } else {
+ component = defaultFailed ? mImageWallpaper : null;
+ finalWhich = which;
+ }
+
+ boolean success = withCleanCallingIdentity(() -> setWallpaperComponent(
+ component, callingPackage, finalWhich, userId));
+ if (success) return;
+ } catch (IllegalArgumentException e1) {
+ e = e1;
+ }
+
+ // This can happen if the default wallpaper component doesn't
+ // exist. This should be a system configuration problem, but
+ // let's not let it crash the system and just live with no
+ // wallpaper.
+ Slog.e(TAG, "Default wallpaper component not found!", e);
+ withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper));
+ }
+
+ // TODO(b/266818039) remove this version of the method
+ private void clearWallpaperLocked(boolean defaultFailed, int which, int userId,
+ IRemoteCallback reply) {
if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
}
@@ -3140,8 +3206,13 @@
// Migrate the bitmap files outright; no need to copy
try {
- Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
- Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
+ if (!mIsLockscreenLiveWallpaperEnabled || sysWP.wallpaperFile.exists()) {
+ Os.rename(sysWP.wallpaperFile.getAbsolutePath(),
+ lockWP.wallpaperFile.getAbsolutePath());
+ }
+ if (!mIsLockscreenLiveWallpaperEnabled || sysWP.cropFile.exists()) {
+ Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
+ }
mLockWallpaperMap.put(userId, lockWP);
if (mIsLockscreenLiveWallpaperEnabled) {
SELinux.restorecon(lockWP.wallpaperFile);
@@ -3204,16 +3275,17 @@
}
@VisibleForTesting
- void setWallpaperComponent(ComponentName name, String callingPackage,
+ boolean setWallpaperComponent(ComponentName name, String callingPackage,
@SetWallpaperFlags int which, int userId) {
if (mIsLockscreenLiveWallpaperEnabled) {
- setWallpaperComponentInternal(name, callingPackage, which, userId);
+ return setWallpaperComponentInternal(name, callingPackage, which, userId);
} else {
setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
+ return true;
}
}
- private void setWallpaperComponentInternal(ComponentName name, String callingPackage,
+ private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage,
@SetWallpaperFlags int which, int userIdIn) {
if (DEBUG) {
Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
@@ -3224,6 +3296,7 @@
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
boolean shouldNotifyColors = false;
+ boolean bindSuccess;
final WallpaperData newWallpaper;
synchronized (mLock) {
@@ -3272,7 +3345,7 @@
*/
boolean forceRebind = same && systemIsBoth && which == FLAG_SYSTEM;
- boolean bindSuccess = bindWallpaperComponentLocked(name, /* force */
+ bindSuccess = bindWallpaperComponentLocked(name, /* force */
forceRebind, /* fromUser */ true, newWallpaper, callback);
if (bindSuccess) {
if (!same) {
@@ -3291,8 +3364,10 @@
});
}
}
+ boolean lockBitmapCleared = false;
if (!mImageWallpaper.equals(newWallpaper.wallpaperComponent)) {
clearWallpaperBitmaps(newWallpaper);
+ lockBitmapCleared = newWallpaper.mWhich == FLAG_LOCK;
}
newWallpaper.wallpaperId = makeWallpaperIdLocked();
notifyCallbacksLocked(newWallpaper);
@@ -3310,6 +3385,9 @@
updateEngineFlags(newWallpaper);
}
}
+ if (!lockBitmapCleared) {
+ clearWallpaperBitmaps(newWallpaper.userId, FLAG_LOCK);
+ }
mLockWallpaperMap.remove(newWallpaper.userId);
}
}
@@ -3322,6 +3400,7 @@
notifyWallpaperColorsChanged(newWallpaper, which);
notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
}
+ return bindSuccess;
}
// TODO(b/266818039) Remove this method
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9af34bc..3be586e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2439,7 +2439,7 @@
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, activityAllDrawn, snapshot);
- //TODO(191787740) Remove for T+
+ //TODO(191787740) Remove for V+
final boolean useLegacy = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN
&& mWmService.mStartingSurfaceController.isExceptionApp(packageName, mTargetSdk,
() -> {
@@ -4295,6 +4295,7 @@
mTaskSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
mTaskSupervisor.mStoppingActivities.remove(this);
+ mLetterboxUiController.destroy();
waitingToShow = false;
// Defer removal of this activity when either a child is animating, or app transition is on
@@ -4364,8 +4365,6 @@
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
}
- mLetterboxUiController.destroy();
-
if (!delayed) {
updateReportedVisibilityLocked();
}
@@ -4565,6 +4564,13 @@
* immediately finishes after, so we have to transfer T to M.
*/
void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
+ final WindowState mainWin = findMainWindow(false);
+ if (mainWin != null && mainWin.mWinAnimator.getShown()) {
+ // This activity already has a visible window, so doesn't need to transfer the starting
+ // window from above activity to here. The starting window will be removed with above
+ // activity.
+ return;
+ }
task.forAllActivities(fromActivity -> {
if (fromActivity == this) return true;
return !fromActivity.isVisibleRequested() && transferStartingWindow(fromActivity);
@@ -8315,6 +8321,8 @@
}
mIsAspectRatioApplied = false;
+ mIsEligibleForFixedOrientationLetterbox = false;
+ mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
// Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
// different from windowing mode of the task (PiP) during transition from fullscreen to PiP
@@ -8324,8 +8332,11 @@
final boolean isFixedOrientationLetterboxAllowed =
parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
|| parentWindowingMode == WINDOWING_MODE_FULLSCREEN
- // Switching from PiP to fullscreen.
- || (parentWindowingMode == WINDOWING_MODE_PINNED
+ // When starting to switch between PiP and fullscreen, the task is pinned
+ // and the activity is fullscreen. But only allow to apply letterbox if the
+ // activity is exiting PiP because an entered PiP should fill the task.
+ || (!mWaitForEnteringPinnedMode
+ && parentWindowingMode == WINDOWING_MODE_PINNED
&& resolvedConfig.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN);
// TODO(b/181207944): Consider removing the if condition and always run
@@ -8719,8 +8730,6 @@
* in this method.
*/
private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
- mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
- mIsEligibleForFixedOrientationLetterbox = false;
final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
final Rect stableBounds = new Rect();
// If orientation is respected when insets are applied, then stableBounds will be empty.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index dba65b2..dce3a38 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -897,6 +897,11 @@
}
mLastStartReason = request.reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
+ // Reset the ActivityRecord#mCurrentLaunchCanTurnScreenOn state of last start activity in
+ // case the state is not yet consumed during rapid activity launch.
+ if (mLastStartActivityRecord != null) {
+ mLastStartActivityRecord.setCurrentLaunchCanTurnScreenOn(false);
+ }
mLastStartActivityRecord = null;
final IApplicationThread caller = request.caller;
@@ -1572,8 +1577,10 @@
// existence change.
transitionController.collectExistenceChange(started);
} else if (result == START_DELIVERED_TO_TOP && newTransition != null
- // An activity has changed order/visibility so this isn't just deliver-to-top
- && mMovedToTopActivity == null) {
+ // An activity has changed order/visibility or the task is occluded by a transient
+ // activity, so this isn't just deliver-to-top
+ && mMovedToTopActivity == null
+ && !transitionController.isTransientHide(startedActivityRootTask)) {
// We just delivered to top, so there isn't an actual transition here.
if (!forceTransientTransition) {
newTransition.abort();
@@ -1683,7 +1690,9 @@
}
// When running transient transition, the transient launch target should keep on top.
// So disallow the transient hide activity to move itself to front, e.g. trampoline.
- if (!mAvoidMoveToFront && r.mTransitionController.isTransientHide(targetTask)) {
+ if (!mAvoidMoveToFront && (mService.mHomeProcess == null
+ || mService.mHomeProcess.mUid != realCallingUid)
+ && r.mTransitionController.isTransientHide(targetTask)) {
mAvoidMoveToFront = true;
}
mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());
@@ -2965,7 +2974,9 @@
// should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
final boolean wasTopOfVisibleRootTask = intentActivity.isVisibleRequested()
&& intentActivity.inMultiWindowMode()
- && intentActivity == mTargetRootTask.topRunningActivity();
+ && intentActivity == mTargetRootTask.topRunningActivity()
+ && !intentActivity.mTransitionController.isTransientHide(
+ mTargetRootTask);
// We only want to move to the front, if we aren't going to launch on a
// different root task. If we launch on a different root task, we will put the
// task on top there.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a650d77..4a658d6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1411,29 +1411,39 @@
final long origId = Binder.clearCallingIdentity();
// TODO(b/64750076): Check if calling pid should really be -1.
- final int res = getActivityStartController()
- .obtainStarter(intent, "startNextMatchingActivity")
- .setCaller(r.app.getThread())
- .setResolvedType(r.resolvedType)
- .setActivityInfo(aInfo)
- .setResultTo(resultTo != null ? resultTo.token : null)
- .setResultWho(resultWho)
- .setRequestCode(requestCode)
- .setCallingPid(-1)
- .setCallingUid(r.launchedFromUid)
- .setCallingPackage(r.launchedFromPackage)
- .setCallingFeatureId(r.launchedFromFeatureId)
- .setRealCallingPid(-1)
- .setRealCallingUid(r.launchedFromUid)
- .setActivityOptions(options)
- .execute();
- Binder.restoreCallingIdentity(origId);
+ try {
+ if (options == null) {
+ options = new SafeActivityOptions(ActivityOptions.makeBasic());
+ }
- r.finishing = wasFinishing;
- if (res != ActivityManager.START_SUCCESS) {
- return false;
+ // Fixes b/230492947
+ // Prevents background activity launch through #startNextMatchingActivity
+ // An activity going into the background could still go back to the foreground
+ // if the intent used matches both:
+ // - the activity in the background
+ // - a second activity.
+ options.getOptions(r).setAvoidMoveToFront();
+ final int res = getActivityStartController()
+ .obtainStarter(intent, "startNextMatchingActivity")
+ .setCaller(r.app.getThread())
+ .setResolvedType(r.resolvedType)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo != null ? resultTo.token : null)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setCallingPid(-1)
+ .setCallingUid(r.launchedFromUid)
+ .setCallingPackage(r.launchedFromPackage)
+ .setCallingFeatureId(r.launchedFromFeatureId)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(r.launchedFromUid)
+ .setActivityOptions(options)
+ .execute();
+ r.finishing = wasFinishing;
+ return res == ActivityManager.START_SUCCESS;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- return true;
}
}
@@ -2012,7 +2022,7 @@
synchronized (mGlobalLock) {
final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
if (dc == null) return;
- final Task task = dc.getTask((t) -> t.isLeafTask() && t.isFocusable(),
+ final Task task = dc.getTask((t) -> t.isLeafTask() && t.isTopActivityFocusable(),
true /* traverseTopToBottom */);
if (task == null) return;
setFocusedTask(task.mTaskId, null /* touchedActivity */);
@@ -4505,8 +4515,12 @@
// to set debug system properties. To ensure that system properties are set
// only when allowed, we check the current UID.
if (Process.myUid() == Process.SYSTEM_UID) {
- SystemProperties.set("debug.tracing.mcc", Integer.toString(values.mcc));
- SystemProperties.set("debug.tracing.mnc", Integer.toString(values.mnc));
+ if (values.mcc != 0) {
+ SystemProperties.set("debug.tracing.mcc", Integer.toString(values.mcc));
+ }
+ if (values.mnc != 0) {
+ SystemProperties.set("debug.tracing.mnc", Integer.toString(values.mnc));
+ }
}
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 3c97672..738797b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1891,7 +1891,7 @@
// DestroyActivityItem may be called first.
final ActivityRecord top = task.getTopMostActivity();
if (top != null && top.finishing && !top.mAppStopped && top.lastVisibleTime > 0
- && !task.mKillProcessesOnDestroyed) {
+ && !task.mKillProcessesOnDestroyed && top.hasProcess()) {
task.mKillProcessesOnDestroyed = true;
mHandler.sendMessageDelayed(
mHandler.obtainMessage(KILL_TASK_PROCESSES_TIMEOUT_MSG, task),
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 7e78393..0115877 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -185,6 +185,8 @@
}
} else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS) {
action = Operation.ACTION_SEAMLESS;
+ } else if (mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
+ return;
}
mTargetWindowTokens.put(w.mToken, new Operation(action));
return;
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index e91c9d4..2b6b62e 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -80,8 +80,8 @@
appendLog("not in bounds phase, skipping");
return RESULT_SKIP;
}
- if (!task.isActivityTypeStandard()) {
- appendLog("not standard activity type, skipping");
+ if (!task.isActivityTypeStandardOrUndefined()) {
+ appendLog("not standard or undefined activity type, skipping");
return RESULT_SKIP;
}
if (!currentParams.mBounds.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 9740d1f..79657c3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2285,8 +2285,8 @@
&& Arrays.equals(mLastLetterboxDetails, letterboxDetails)) {
return;
}
- if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
- && ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
+ if (mDisplayContent.isDefaultDisplay && (mLastFocusIsFullscreen != isFullscreen
+ || ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0)) {
mService.mInputManager.setSystemUiLightsOut(
isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 1fbf593..2b34bb2 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -42,6 +42,7 @@
import android.app.servertransaction.RefreshCallbackItem;
import android.app.servertransaction.ResumeActivityItem;
import android.content.pm.ActivityInfo.ScreenOrientation;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.camera2.CameraManager;
import android.os.Handler;
@@ -423,7 +424,18 @@
// for the activity embedding case.
if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
&& isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
- showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
+ final PackageManager packageManager = mWmService.mContext.getPackageManager();
+ try {
+ showToast(
+ R.string.display_rotation_camera_compat_toast_in_multi_window,
+ (String) packageManager.getApplicationLabel(
+ packageManager.getApplicationInfo(packageName, /* flags */ 0)));
+ } catch (PackageManager.NameNotFoundException e) {
+ ProtoLog.e(WM_DEBUG_ORIENTATION,
+ "DisplayRotationCompatPolicy: Multi-window toast not shown as "
+ + "package '%s' cannot be found.",
+ packageName);
+ }
}
}
}
@@ -434,6 +446,15 @@
() -> Toast.makeText(mWmService.mContext, stringRes, Toast.LENGTH_LONG).show());
}
+ @VisibleForTesting
+ void showToast(@StringRes int stringRes, @NonNull String applicationLabel) {
+ UiThread.getHandler().post(
+ () -> Toast.makeText(
+ mWmService.mContext,
+ mWmService.mContext.getString(stringRes, applicationLabel),
+ Toast.LENGTH_LONG).show());
+ }
+
private synchronized void notifyCameraClosed(@NonNull String cameraId) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d is notified that Camera %s is closed, scheduling rotation update.",
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 44d6768..98027bb 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -23,6 +23,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowStateProto.IDENTIFIER;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
@@ -217,10 +218,10 @@
mHostWindowState.mInputWindowHandle.getInputApplicationHandle());
}
- InputChannel openInputChannel() {
+ void openInputChannel(@NonNull InputChannel outInputChannel) {
final String name = toString();
mInputChannel = mWmService.mInputManager.createInputChannel(name);
- return mInputChannel;
+ mInputChannel.copyTo(outInputChannel);
}
void onRemoved() {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 21004ab..e1c865b 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -454,7 +454,7 @@
if (mSource.getType() == WindowInsets.Type.ime()) {
setClientVisible(target.isRequestedVisible(WindowInsets.Type.ime()));
}
- final Transaction t = mDisplayContent.getSyncTransaction();
+ final Transaction t = mWindowContainer.getSyncTransaction();
mWindowContainer.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
ANIMATION_TYPE_INSETS_CONTROL);
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 07f3bc6..0af9fe9 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -15,6 +15,7 @@
lihongyu@google.com
mariiasand@google.com
rgl@google.com
+yunfanc@google.com
per-file BackgroundActivityStartController.java = set noparent
per-file BackgroundActivityStartController.java = brufino@google.com, ogunwale@google.com, louischang@google.com, lus@google.com, rickywai@google.com
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4995236..adaecc2 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -102,6 +102,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserProperties;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -148,6 +149,7 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.utils.Slogf;
@@ -1879,6 +1881,14 @@
rootTask.switchUser(userId);
});
+
+ if (topFocusedRootTask != null && isAlwaysVisibleUser(topFocusedRootTask.mUserId)) {
+ Slog.i(TAG, "Persisting top task because it belongs to an always-visible user");
+ // For a normal user-switch, we will restore the new user's task. But if the pre-switch
+ // top task is an always-visible (Communal) one, keep it even after the switch.
+ mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
+ }
+
final int restoreRootTaskId = mUserRootTaskInFront.get(userId);
Task rootTask = getRootTask(restoreRootTaskId);
if (rootTask == null) {
@@ -1894,6 +1904,13 @@
return homeInFront;
}
+ /** Returns whether the given user is to be always-visible (e.g. a communal profile). */
+ private boolean isAlwaysVisibleUser(@UserIdInt int userId) {
+ final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ final UserProperties properties = umi.getUserProperties(userId);
+ return properties != null && properties.getAlwaysVisible();
+ }
+
void removeUser(int userId) {
mUserRootTaskInFront.delete(userId);
}
@@ -2013,7 +2030,6 @@
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
r.setWindowingMode(r.getWindowingMode());
- r.mWaitForEnteringPinnedMode = true;
final TaskFragment organizedTf = r.getOrganizedTaskFragment();
final boolean singleActivity = task.getNonFinishingActivityCount() == 1;
@@ -2140,6 +2156,10 @@
}
rootTask.setDeferTaskAppear(false);
+ // After setting this, it is not expected to change activity configuration until the
+ // transition animation is finished. So the activity can keep consistent appearance
+ // when animating.
+ r.mWaitForEnteringPinnedMode = true;
// Reset the state that indicates it can enter PiP while pausing after we've moved it
// to the root pinned task
r.supportsEnterPipOnTaskSwitch = false;
@@ -2357,10 +2377,14 @@
final Transition transition = new Transition(TRANSIT_SLEEP, 0 /* flags */,
display.mTransitionController, mWmService.mSyncEngine);
final TransitionController.OnStartCollect sendSleepTransition = (deferred) -> {
- display.mTransitionController.requestStartTransition(transition,
- null /* trigger */, null /* remote */, null /* display */);
- // Force playing immediately so that unrelated ops can't be collected.
- transition.playNow();
+ if (deferred && !display.shouldSleep()) {
+ transition.abort();
+ } else {
+ display.mTransitionController.requestStartTransition(transition,
+ null /* trigger */, null /* remote */, null /* display */);
+ // Force playing immediately so that unrelated ops can't be collected.
+ transition.playNow();
+ }
};
if (!display.mTransitionController.isCollecting()) {
// Since this bypasses sync, submit directly ignoring whether sync-engine
@@ -3306,9 +3330,14 @@
if (aOptions != null) {
// Resolve the root task the task should be placed in now based on options
// and reparent if needed.
+ // TODO(b/229927851) For split-screen, setLaunchRootTask is no longer the "root"
+ // task, consider to rename methods like "parentTask" instead of "rootTask".
final Task targetRootTask =
getOrCreateRootTask(null, aOptions, task, onTop);
- if (targetRootTask != null && task.getRootTask() != targetRootTask) {
+ // When launch with ActivityOptions#getLaunchRootTask, the "root task" just mean the
+ // parent of current launch, not the "root task" in hierarchy.
+ if (targetRootTask != null && task.getRootTask() != targetRootTask
+ && task.getParent() != targetRootTask) {
final int reparentMode = onTop
? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
task.reparent(targetRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,
diff --git a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
index b3cd3f0..3fb897b 100644
--- a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
+++ b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
@@ -70,7 +70,7 @@
}
/**
- * Returns true if the packageName is in the list and the target sdk is before or including T.
+ * Returns true if the packageName is in the list and the target sdk is before or including V.
*
* @param packageName The package name of the application to check
* @param targetSdk The target sdk of the application
@@ -82,7 +82,7 @@
@SuppressWarnings("AndroidFrameworkCompatChange") // Target sdk check
public boolean isException(@NonNull String packageName, int targetSdk,
@Nullable Supplier<ApplicationInfo> infoSupplier) {
- if (targetSdk > Build.VERSION_CODES.TIRAMISU) {
+ if (targetSdk > Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index 878b33f..1007357 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -20,6 +20,8 @@
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
+import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
+import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
import android.annotation.NonNull;
import android.content.Context;
@@ -59,6 +61,12 @@
private static final int SWIPE_FROM_RIGHT = 3;
private static final int SWIPE_FROM_LEFT = 4;
+ private static final int TRACKPAD_SWIPE_NONE = 0;
+ private static final int TRACKPAD_SWIPE_FROM_TOP = 1;
+ private static final int TRACKPAD_SWIPE_FROM_BOTTOM = 2;
+ private static final int TRACKPAD_SWIPE_FROM_RIGHT = 3;
+ private static final int TRACKPAD_SWIPE_FROM_LEFT = 4;
+
private final Context mContext;
private final Handler mHandler;
private int mDisplayCutoutTouchableRegionSize;
@@ -207,6 +215,25 @@
break;
case MotionEvent.ACTION_MOVE:
if (mSwipeFireable) {
+ int trackpadSwipe = detectTrackpadThreeFingerSwipe(event);
+ mSwipeFireable = trackpadSwipe == TRACKPAD_SWIPE_NONE;
+ if (!mSwipeFireable) {
+ if (trackpadSwipe == TRACKPAD_SWIPE_FROM_TOP) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop from trackpad");
+ mCallbacks.onSwipeFromTop();
+ } else if (trackpadSwipe == TRACKPAD_SWIPE_FROM_BOTTOM) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom from trackpad");
+ mCallbacks.onSwipeFromBottom();
+ } else if (trackpadSwipe == TRACKPAD_SWIPE_FROM_RIGHT) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight from trackpad");
+ mCallbacks.onSwipeFromRight();
+ } else if (trackpadSwipe == TRACKPAD_SWIPE_FROM_LEFT) {
+ if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft from trackpad");
+ mCallbacks.onSwipeFromLeft();
+ }
+ break;
+ }
+
final int swipe = detectSwipe(event);
mSwipeFireable = swipe == SWIPE_NONE;
if (swipe == SWIPE_FROM_TOP) {
@@ -300,6 +327,31 @@
return mDownPointers - 1;
}
+ private int detectTrackpadThreeFingerSwipe(MotionEvent move) {
+ if (!isTrackpadThreeFingerSwipe(move)) {
+ return TRACKPAD_SWIPE_NONE;
+ }
+
+ float dx = move.getX() - mDownX[0];
+ float dy = move.getY() - mDownY[0];
+ if (Math.abs(dx) < Math.abs(dy)) {
+ if (Math.abs(dy) > mSwipeDistanceThreshold) {
+ return dy > 0 ? TRACKPAD_SWIPE_FROM_TOP : TRACKPAD_SWIPE_FROM_BOTTOM;
+ }
+ } else {
+ if (Math.abs(dx) > mSwipeDistanceThreshold) {
+ return dx > 0 ? TRACKPAD_SWIPE_FROM_LEFT : TRACKPAD_SWIPE_FROM_RIGHT;
+ }
+ }
+
+ return TRACKPAD_SWIPE_NONE;
+ }
+
+ private static boolean isTrackpadThreeFingerSwipe(MotionEvent event) {
+ return event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE
+ && event.getAxisValue(AXIS_GESTURE_SWIPE_FINGER_COUNT) == 3;
+ }
+
private int detectSwipe(MotionEvent move) {
final int historySize = move.getHistorySize();
final int pointerCount = move.getPointerCount();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1ae1e03..39772dda 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3298,6 +3298,12 @@
scheduleAnimation();
}
+ // Let organizer manage task visibility for shell transition. So don't change it's
+ // visibility during collecting.
+ if (mTransitionController.isCollecting() && mCreatedByOrganizer) {
+ return;
+ }
+
// We intend to let organizer manage task visibility but it doesn't
// have enough information until we finish shell transitions.
// In the mean time we do an easy fix here.
@@ -3445,6 +3451,7 @@
: INVALID_TASK_ID;
info.isFocused = isFocused();
info.isVisible = hasVisibleChildren();
+ info.isVisibleRequested = isVisibleRequested();
info.isSleeping = shouldSleepActivities();
info.isLetterboxDoubleTapEnabled = top != null
&& top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
@@ -5695,17 +5702,28 @@
}
private boolean moveTaskToBackInner(@NonNull Task task) {
- moveToBack("moveTaskToBackInner", task);
-
- if (inPinnedWindowingMode()) {
- mTaskSupervisor.removeRootTask(this);
- return true;
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ // Preventing from update surface position for WindowState if configuration changed,
+ // because the position is depends on WindowFrame, so update the position before
+ // relayout will only update it to "old" position.
+ mAtmService.deferWindowLayout();
}
+ try {
+ moveToBack("moveTaskToBackInner", task);
- mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
- false /* deferResume */);
+ if (inPinnedWindowingMode()) {
+ mTaskSupervisor.removeRootTask(this);
+ return true;
+ }
+ mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
+ mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
+ false /* deferResume */);
+ } finally {
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ mAtmService.continueWindowLayout();
+ }
+ }
ActivityRecord topActivity = getDisplayArea().topRunningActivity();
Task topRootTask = topActivity.getRootTask();
if (topRootTask != null && topRootTask != this && topActivity.isState(RESUMED)) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index c6c3b14..0c1f33c 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1017,8 +1017,11 @@
if (isTopActivityLaunchedBehind()) {
return TASK_FRAGMENT_VISIBILITY_VISIBLE;
}
+ final WindowContainer<?> parent = getParent();
final Task thisTask = asTask();
- if (thisTask != null && mTransitionController.isTransientHide(thisTask)) {
+ if (thisTask != null && parent.asTask() == null
+ && mTransitionController.isTransientHide(thisTask)) {
+ // Keep transient-hide root tasks visible. Non-root tasks still follow standard rule.
return TASK_FRAGMENT_VISIBILITY_VISIBLE;
}
@@ -1028,7 +1031,6 @@
// This TaskFragment is only considered visible if all its parent TaskFragments are
// considered visible, so check the visibility of all ancestor TaskFragment first.
- final WindowContainer parent = getParent();
if (parent.asTaskFragment() != null) {
final int parentVisibility = parent.asTaskFragment().getVisibility(starting);
if (parentVisibility == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 9a5f766..aad1225 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -234,9 +234,6 @@
private @TransitionState int mState = STATE_PENDING;
private final ReadyTracker mReadyTracker = new ReadyTracker();
- // TODO(b/188595497): remove when not needed.
- /** @see RecentsAnimationController#mNavigationBarAttachedToApp */
- private boolean mNavBarAttachedToApp = false;
private int mRecentsDisplayId = INVALID_DISPLAY;
/** The delay for light bar appearance animation. */
@@ -690,6 +687,7 @@
if (!wc.mDisplayContent.getDisplayPolicy().isScreenOnFully()
|| wc.mDisplayContent.getDisplayInfo().state == Display.STATE_OFF) {
mFlags |= WindowManager.TRANSIT_FLAG_INVISIBLE;
+ return;
}
if (mContainerFreezer == null) {
@@ -1190,7 +1188,11 @@
// processed all the participants first (in particular, we want to trigger pip-enter first)
for (int i = 0; i < mParticipants.size(); ++i) {
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
- if (ar != null) {
+ // If the activity was just inserted to an invisible task, it will keep INITIALIZING
+ // state. Then no need to notify the callback to avoid clearing some states
+ // unexpectedly, e.g. launch-task-behind.
+ if (ar != null && (ar.isVisibleRequested()
+ || !ar.isState(ActivityRecord.State.INITIALIZING))) {
mController.dispatchLegacyAppTransitionFinished(ar);
}
}
@@ -1776,7 +1778,7 @@
if (navWindow == null || navWindow.mToken == null) {
return;
}
- mNavBarAttachedToApp = true;
+ mController.mNavigationBarAttachedToApp = true;
navWindow.mToken.cancelAnimation();
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
@@ -1798,8 +1800,10 @@
/** @see RecentsAnimationController#restoreNavigationBarFromApp */
void legacyRestoreNavigationBarFromApp() {
- if (!mNavBarAttachedToApp) return;
- mNavBarAttachedToApp = false;
+ if (!mController.mNavigationBarAttachedToApp) {
+ return;
+ }
+ mController.mNavigationBarAttachedToApp = false;
if (mRecentsDisplayId == INVALID_DISPLAY) {
Slog.e(TAG, "Reparented navigation bar without a valid display");
@@ -1832,6 +1836,11 @@
break;
}
+ final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
+ if (asyncRotationController != null) {
+ asyncRotationController.accept(navWindow);
+ }
+
if (animate) {
final NavBarFadeAnimationController controller =
new NavBarFadeAnimationController(dc);
@@ -1840,6 +1849,9 @@
// Reparent the SurfaceControl of nav bar token back.
t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
}
+
+ // To apply transactions.
+ dc.mWmService.scheduleAnimationLocked();
}
private void reportStartReasonsToLogger() {
@@ -2244,11 +2256,17 @@
WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, wc);
// Make leash based on highest (z-order) direct child of ancestor with a participant.
+ // Check whether the ancestor is belonged to last parent, shouldn't happen.
+ final boolean hasReparent = !wc.isDescendantOf(ancestor);
WindowContainer leashReference = wc;
- while (leashReference.getParent() != ancestor) {
- leashReference = leashReference.getParent();
+ if (hasReparent) {
+ Slog.e(TAG, "Did not find common ancestor! Ancestor= " + ancestor
+ + " target= " + wc);
+ } else {
+ while (leashReference.getParent() != ancestor) {
+ leashReference = leashReference.getParent();
+ }
}
-
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
"Transition Root: " + leashReference.getName()).build();
rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
@@ -2307,23 +2325,13 @@
task.fillTaskInfo(tinfo);
change.setTaskInfo(tinfo);
change.setRotationAnimation(getTaskRotationAnimation(task));
- final ActivityRecord topMostActivity = task.getTopMostActivity();
- change.setAllowEnterPip(topMostActivity != null
- && topMostActivity.checkEnterPictureInPictureAppOpsState());
final ActivityRecord topRunningActivity = task.topRunningActivity();
- if (topRunningActivity != null && task.mDisplayContent != null
- // Display won't be rotated for multi window Task, so the fixed rotation
- // won't be applied. This can happen when the windowing mode is changed
- // before the previous fixed rotation is applied.
- && (!task.inMultiWindowMode() || !topRunningActivity.inMultiWindowMode())) {
- // If Activity is in fixed rotation, its will be applied with the next rotation,
- // when the Task is still in the previous rotation.
- final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
- final int activityRotation = topRunningActivity.getWindowConfiguration()
- .getDisplayRotation();
- if (taskRotation != activityRotation) {
- change.setEndFixedRotation(activityRotation);
+ if (topRunningActivity != null) {
+ if (topRunningActivity.info.supportsPictureInPicture()) {
+ change.setAllowEnterPip(
+ topRunningActivity.checkEnterPictureInPictureAppOpsState());
}
+ setEndFixedRotationIfNeeded(change, task, topRunningActivity);
}
} else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {
change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);
@@ -2431,6 +2439,48 @@
}
return animOptions;
}
+
+ private static void setEndFixedRotationIfNeeded(@NonNull TransitionInfo.Change change,
+ @NonNull Task task, @NonNull ActivityRecord taskTopRunning) {
+ if (!taskTopRunning.isVisibleRequested()) {
+ // Fixed rotation only applies to opening or changing activity.
+ return;
+ }
+ if (task.inMultiWindowMode() && taskTopRunning.inMultiWindowMode()) {
+ // Display won't be rotated for multi window Task, so the fixed rotation won't be
+ // applied. This can happen when the windowing mode is changed before the previous
+ // fixed rotation is applied. Check both task and activity because the activity keeps
+ // fullscreen mode when the task is entering PiP.
+ return;
+ }
+ final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
+ final int activityRotation = taskTopRunning.getWindowConfiguration()
+ .getDisplayRotation();
+ // If the Activity uses fixed rotation, its rotation will be applied to display after
+ // the current transition is done, while the Task is still in the previous rotation.
+ if (taskRotation != activityRotation) {
+ change.setEndFixedRotation(activityRotation);
+ return;
+ }
+
+ // For example, the task is entering PiP so it no longer decides orientation. If the next
+ // orientation source (it could be an activity which was behind the PiP or launching to top)
+ // will change display rotation, then set the fixed rotation hint as well so the animation
+ // can consider the rotated position.
+ if (!task.inPinnedWindowingMode() || taskTopRunning.mDisplayContent.inTransition()) {
+ return;
+ }
+ final WindowContainer<?> orientationSource =
+ taskTopRunning.mDisplayContent.getLastOrientationSource();
+ if (orientationSource == null) {
+ return;
+ }
+ final int nextRotation = orientationSource.getWindowConfiguration().getDisplayRotation();
+ if (taskRotation != nextRotation) {
+ change.setEndFixedRotation(nextRotation);
+ }
+ }
+
/**
* Finds the top-most common ancestor of app targets.
*
@@ -2453,6 +2503,20 @@
// Skip the non-app window or windows on a different display
continue;
}
+ // Re-initiate the last parent as the initial ancestor instead of the top target.
+ // When move a leaf task from organized task to display area, try to keep the transition
+ // root be the original organized task for close transition animation.
+ // Otherwise, shell will use wrong root layer to play animation.
+ // Note: Since the target is sorted, so only need to do this at the lowest target.
+ if (change.mStartParent != null && wc.getParent() != null
+ && change.mStartParent.isAttached() && wc.getParent() != change.mStartParent
+ && i == targets.size() - 1) {
+ final int transitionMode = change.getTransitMode(wc);
+ if (transitionMode == TRANSIT_CLOSE || transitionMode == TRANSIT_TO_BACK) {
+ ancestor = change.mStartParent;
+ continue;
+ }
+ }
while (!wc.isDescendantOf(ancestor)) {
ancestor = ancestor.getParent();
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0cb6f14..359b353 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -206,6 +206,11 @@
*/
boolean mBuildingFinishLayers = false;
+ /**
+ * Whether the surface of navigation bar token is reparented to an app.
+ */
+ boolean mNavigationBarAttachedToApp = false;
+
private boolean mAnimatingState = false;
final Handler mLoggerHandler = FgThread.getHandler();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c4e3aae..763c4d6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -88,6 +88,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.fixScale;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
@@ -3589,6 +3590,7 @@
public void setCurrentUser(@UserIdInt int newUserId) {
synchronized (mGlobalLock) {
+ mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_OPEN, null);
mCurrentUserId = newUserId;
mPolicy.setCurrentUserLw(newUserId);
mKeyguardDisableHandler.setCurrentUser(newUserId);
@@ -8767,24 +8769,22 @@
final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);
final InputApplicationHandle applicationHandle;
final String name;
- final InputChannel clientChannel;
+ Objects.requireNonNull(outInputChannel);
synchronized (mGlobalLock) {
EmbeddedWindowController.EmbeddedWindow win =
new EmbeddedWindowController.EmbeddedWindow(session, this, window,
mInputToWindowMap.get(hostInputToken), callingUid, callingPid,
sanitizedType, displayId, focusGrantToken, inputHandleName,
(flags & FLAG_NOT_FOCUSABLE) == 0);
- clientChannel = win.openInputChannel();
- mEmbeddedWindowController.add(clientChannel.getToken(), win);
+ win.openInputChannel(outInputChannel);
+ mEmbeddedWindowController.add(outInputChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
name = win.toString();
}
- updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
+ updateInputChannel(outInputChannel.getToken(), callingUid, callingPid, displayId, surface,
name, applicationHandle, flags, privateFlags, inputFeatures, sanitizedType,
null /* region */, window);
-
- clientChannel.copyTo(outInputChannel);
}
boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 3672820..d7d2b4e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -563,7 +563,7 @@
return;
}
- final long diff = lastLaunchTime - launchTime;
+ final long diff = launchTime - lastLaunchTime;
if (diff < RAPID_ACTIVITY_LAUNCH_MS) {
mRapidActivityLaunchCount++;
} else if (diff >= RESET_RAPID_ACTIVITY_LAUNCH_MS) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b52935e..a1473b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3887,15 +3887,13 @@
}
/**
- * @return {@code true} if activity bounds are letterboxed or letterboxed for display cutout.
- * Note that it's always {@code false} if the activity is in pip mode.
+ * Returns {@code true} if activity bounds are letterboxed or letterboxed for display cutout.
*
* <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link
* LetterboxUiController#shouldShowLetterboxUi} for more context.
*/
boolean areAppWindowBoundsLetterboxed() {
return mActivityRecord != null
- && !mActivityRecord.inPinnedWindowingMode()
&& (mActivityRecord.areBoundsLetterboxed() || isLetterboxedForDisplayCutout());
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 1ecc162..3ba4170 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -352,6 +352,8 @@
void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
void setPointerCapture(const PointerCaptureRequest& request) override;
void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
+ void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
+ const std::set<int32_t>& uids) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -963,6 +965,15 @@
checkAndClearExceptionFromCallback(env, "notifyDropWindow");
}
+void NativeInputManager::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
+ const std::set<int32_t>& uids) {
+ static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
+ sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
+ if (!ENABLE_INPUT_DEVICE_USAGE_METRICS) return;
+
+ mInputManager->getMetricsCollector().notifyDeviceInteraction(deviceId, timestamp, uids);
+}
+
void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
const std::vector<float>& values) {
@@ -1159,6 +1170,8 @@
}
void NativeInputManager::setInputDeviceEnabled(uint32_t deviceId, bool enabled) {
+ bool refresh = false;
+
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -1166,14 +1179,18 @@
bool currentlyEnabled = it == mLocked.disabledInputDevices.end();
if (!enabled && currentlyEnabled) {
mLocked.disabledInputDevices.insert(deviceId);
+ refresh = true;
}
if (enabled && !currentlyEnabled) {
mLocked.disabledInputDevices.erase(deviceId);
+ refresh = true;
}
} // release lock
- mInputManager->getReader().requestRefreshConfiguration(
- InputReaderConfiguration::Change::ENABLED_STATE);
+ if (refresh) {
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::ENABLED_STATE);
+ }
}
void NativeInputManager::setShowTouches(bool enabled) {
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 f96ca58..7104a80 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -46,6 +46,8 @@
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
+ <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0"
+ maxOccurs="1"/>
<xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
maxOccurs="1"/>
<xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1"/>
@@ -137,6 +139,39 @@
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="luxThrottling">
+ <xs:sequence>
+ <xs:element name="brightnessLimitMap" type="brightnessLimitMap"
+ maxOccurs="unbounded">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="brightnessLimitMap">
+ <xs:sequence>
+ <xs:element name="type" type="PredefinedBrightnessLimitNames">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- lux level from light sensor to screen brightness recommended max value map.
+ Screen brightness recommended max value is to highBrightnessMode.transitionPoint and must be below that -->
+ <xs:element name="map" type="nonNegativeFloatToFloatMap">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Predefined type names as defined by DisplayDeviceConfig.BrightnessLimitMapType -->
+ <xs:simpleType name="PredefinedBrightnessLimitNames">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="adaptive"/>
+ </xs:restriction>
+ </xs:simpleType>
+
<xs:complexType name="highBrightnessMode">
<xs:all>
<xs:element name="transitionPoint" type="nonNegativeDecimal" minOccurs="1"
@@ -575,4 +610,27 @@
<xs:annotation name="final"/>
</xs:element>
</xs:complexType>
+
+ <!-- generic types -->
+ <xs:complexType name="nonNegativeFloatToFloatPoint">
+ <xs:sequence>
+ <xs:element name="first" type="nonNegativeDecimal">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="second" type="nonNegativeDecimal">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="nonNegativeFloatToFloatMap">
+ <xs:sequence>
+ <xs:element name="point" type="nonNegativeFloatToFloatPoint" maxOccurs="unbounded">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
</xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index ad6434e..507c9dc 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -26,6 +26,14 @@
method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint();
}
+ public class BrightnessLimitMap {
+ ctor public BrightnessLimitMap();
+ method @NonNull public final com.android.server.display.config.NonNegativeFloatToFloatMap getMap();
+ method @NonNull public final com.android.server.display.config.PredefinedBrightnessLimitNames getType();
+ method public final void setMap(@NonNull com.android.server.display.config.NonNegativeFloatToFloatMap);
+ method public final void setType(@NonNull com.android.server.display.config.PredefinedBrightnessLimitNames);
+ }
+
public class BrightnessThresholds {
ctor public BrightnessThresholds();
method public final com.android.server.display.config.ThresholdPoints getBrightnessThresholdPoints();
@@ -89,6 +97,7 @@
method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle();
method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
method public final com.android.server.display.config.SensorDetails getLightSensor();
+ method public com.android.server.display.config.LuxThrottling getLuxThrottling();
method @Nullable public final String getName();
method public final com.android.server.display.config.SensorDetails getProxSensor();
method public com.android.server.display.config.DisplayQuirks getQuirks();
@@ -115,6 +124,7 @@
method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
method public final void setLightSensor(com.android.server.display.config.SensorDetails);
+ method public void setLuxThrottling(com.android.server.display.config.LuxThrottling);
method public final void setName(@Nullable String);
method public final void setProxSensor(com.android.server.display.config.SensorDetails);
method public void setQuirks(com.android.server.display.config.DisplayQuirks);
@@ -173,6 +183,11 @@
method public java.util.List<java.math.BigInteger> getItem();
}
+ public class LuxThrottling {
+ ctor public LuxThrottling();
+ method @NonNull public final java.util.List<com.android.server.display.config.BrightnessLimitMap> getBrightnessLimitMap();
+ }
+
public class NitsMap {
ctor public NitsMap();
method public String getInterpolation();
@@ -180,6 +195,19 @@
method public void setInterpolation(String);
}
+ public class NonNegativeFloatToFloatMap {
+ ctor public NonNegativeFloatToFloatMap();
+ method @NonNull public final java.util.List<com.android.server.display.config.NonNegativeFloatToFloatPoint> getPoint();
+ }
+
+ public class NonNegativeFloatToFloatPoint {
+ ctor public NonNegativeFloatToFloatPoint();
+ method @NonNull public final java.math.BigDecimal getFirst();
+ method @NonNull public final java.math.BigDecimal getSecond();
+ method public final void setFirst(@NonNull java.math.BigDecimal);
+ method public final void setSecond(@NonNull java.math.BigDecimal);
+ }
+
public class Point {
ctor public Point();
method @NonNull public final java.math.BigDecimal getNits();
@@ -188,6 +216,12 @@
method public final void setValue(@NonNull java.math.BigDecimal);
}
+ public enum PredefinedBrightnessLimitNames {
+ method public String getRawName();
+ enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default;
+ enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames adaptive;
+ }
+
public class RefreshRateConfigs {
ctor public RefreshRateConfigs();
method public final java.math.BigInteger getDefaultPeakRefreshRate();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index c918fb8..9c1d765 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -101,7 +101,7 @@
private final UserManager mUserManager;
// TODO(b/256849338): add more granular locks
- private final Object mLock = new Object();
+ private final Object mLock;
/**
* Map of <userId, Map<policyKey, policyState>>
@@ -122,9 +122,11 @@
DevicePolicyEngine(
@NonNull Context context,
- @NonNull DeviceAdminServiceController deviceAdminServiceController) {
+ @NonNull DeviceAdminServiceController deviceAdminServiceController,
+ @NonNull Object lock) {
mContext = Objects.requireNonNull(context);
mDeviceAdminServiceController = Objects.requireNonNull(deviceAdminServiceController);
+ mLock = Objects.requireNonNull(lock);
mUserManager = mContext.getSystemService(UserManager.class);
mLocalPolicies = new SparseArray<>();
mGlobalPolicies = new HashMap<>();
@@ -152,8 +154,8 @@
PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
if (policyDefinition.isNonCoexistablePolicy()) {
- setNonCoexistableLocalPolicy(policyDefinition, localPolicyState, enforcingAdmin,
- value, userId, skipEnforcePolicy);
+ setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
+ enforcingAdmin, value, userId, skipEnforcePolicy);
return;
}
@@ -173,7 +175,7 @@
// the data structures.
if (!skipEnforcePolicy) {
if (policyChanged) {
- onLocalPolicyChanged(policyDefinition, enforcingAdmin, userId);
+ onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
}
boolean policyEnforced = Objects.equals(
localPolicyState.getCurrentResolvedPolicy(), value);
@@ -211,7 +213,7 @@
*
* <p>Passing a {@code null} value means the policy set by this admin should be removed.
*/
- private <V> void setNonCoexistableLocalPolicy(
+ private <V> void setNonCoexistableLocalPolicyLocked(
PolicyDefinition<V> policyDefinition,
PolicyState<V> localPolicyState,
EnforcingAdmin enforcingAdmin,
@@ -266,8 +268,8 @@
PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
if (policyDefinition.isNonCoexistablePolicy()) {
- setNonCoexistableLocalPolicy(policyDefinition, localPolicyState, enforcingAdmin,
- /* value= */ null, userId, /* skipEnforcePolicy= */ false);
+ setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
+ enforcingAdmin, /* value= */ null, userId, /* skipEnforcePolicy= */ false);
return;
}
@@ -282,7 +284,7 @@
}
if (policyChanged) {
- onLocalPolicyChanged(policyDefinition, enforcingAdmin, userId);
+ onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
}
// For a removePolicy to be enforced, it means no current policy exists
@@ -348,7 +350,7 @@
/**
* Enforces the new policy and notifies relevant admins.
*/
- private <V> void onLocalPolicyChanged(
+ private <V> void onLocalPolicyChangedLocked(
@NonNull PolicyDefinition<V> policyDefinition,
@NonNull EnforcingAdmin enforcingAdmin,
int userId) {
@@ -358,7 +360,7 @@
policyDefinition, localPolicyState.getCurrentResolvedPolicy(), userId);
// Send policy updates to admins who've set it locally
- sendPolicyChangedToAdmins(
+ sendPolicyChangedToAdminsLocked(
localPolicyState,
enforcingAdmin,
policyDefinition,
@@ -369,7 +371,7 @@
// Send policy updates to admins who've set it globally
if (hasGlobalPolicyLocked(policyDefinition)) {
PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
- sendPolicyChangedToAdmins(
+ sendPolicyChangedToAdminsLocked(
globalPolicyState,
enforcingAdmin,
policyDefinition,
@@ -424,7 +426,7 @@
// the data structures.
if (!skipEnforcePolicy) {
if (policyChanged) {
- onGlobalPolicyChanged(policyDefinition, enforcingAdmin);
+ onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
}
boolean policyAppliedGlobally = Objects.equals(
@@ -473,7 +475,7 @@
boolean policyChanged = policyState.removePolicy(enforcingAdmin);
if (policyChanged) {
- onGlobalPolicyChanged(policyDefinition, enforcingAdmin);
+ onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
}
applyGlobalPolicyOnUsersWithLocalPoliciesLocked(policyDefinition, enforcingAdmin,
@@ -499,7 +501,7 @@
/**
* Enforces the new policy globally and notifies relevant admins.
*/
- private <V> void onGlobalPolicyChanged(
+ private <V> void onGlobalPolicyChangedLocked(
@NonNull PolicyDefinition<V> policyDefinition,
@NonNull EnforcingAdmin enforcingAdmin) {
PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
@@ -507,7 +509,7 @@
enforcePolicy(policyDefinition, policyState.getCurrentResolvedPolicy(),
UserHandle.USER_ALL);
- sendPolicyChangedToAdmins(
+ sendPolicyChangedToAdminsLocked(
policyState,
enforcingAdmin,
policyDefinition,
@@ -552,7 +554,7 @@
policyDefinition,
localPolicyState.getCurrentResolvedPolicy(),
userId);
- sendPolicyChangedToAdmins(
+ sendPolicyChangedToAdminsLocked(
localPolicyState,
enforcingAdmin,
policyDefinition,
@@ -745,34 +747,35 @@
}
<V> void transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin) {
- Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
- for (PolicyKey policy : globalPolicies) {
- PolicyState<?> policyState = mGlobalPolicies.get(policy);
- if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
- PolicyDefinition<V> policyDefinition =
- (PolicyDefinition<V>) policyState.getPolicyDefinition();
- PolicyValue<V> policyValue =
- (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
- setGlobalPolicy(policyDefinition, newAdmin, policyValue);
- }
- }
-
- for (int i = 0; i < mLocalPolicies.size(); i++) {
- int userId = mLocalPolicies.keyAt(i);
- Set<PolicyKey> localPolicies = new HashSet<>(
- mLocalPolicies.get(userId).keySet());
- for (PolicyKey policy : localPolicies) {
- PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ synchronized (mLock) {
+ Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
+ for (PolicyKey policy : globalPolicies) {
+ PolicyState<?> policyState = mGlobalPolicies.get(policy);
if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
PolicyDefinition<V> policyDefinition =
(PolicyDefinition<V>) policyState.getPolicyDefinition();
PolicyValue<V> policyValue =
(PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
- setLocalPolicy(policyDefinition, newAdmin, policyValue, userId);
+ setGlobalPolicy(policyDefinition, newAdmin, policyValue);
+ }
+ }
+
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ int userId = mLocalPolicies.keyAt(i);
+ Set<PolicyKey> localPolicies = new HashSet<>(
+ mLocalPolicies.get(userId).keySet());
+ for (PolicyKey policy : localPolicies) {
+ PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
+ setLocalPolicy(policyDefinition, newAdmin, policyValue, userId);
+ }
}
}
}
-
removePoliciesForAdmin(oldAdmin);
}
@@ -836,7 +839,7 @@
mLocalPolicies.get(userId).put(
policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
}
- return getPolicyState(mLocalPolicies.get(userId), policyDefinition);
+ return getPolicyStateLocked(mLocalPolicies.get(userId), policyDefinition);
}
private <V> void removeLocalPolicyStateLocked(
@@ -858,14 +861,14 @@
mGlobalPolicies.put(
policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
}
- return getPolicyState(mGlobalPolicies, policyDefinition);
+ return getPolicyStateLocked(mGlobalPolicies, policyDefinition);
}
private <V> void removeGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) {
mGlobalPolicies.remove(policyDefinition.getPolicyKey());
}
- private static <V> PolicyState<V> getPolicyState(
+ private static <V> PolicyState<V> getPolicyStateLocked(
Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) {
try {
// This will not throw an exception because policyDefinition is of type V, so unless
@@ -935,7 +938,7 @@
}
// TODO(b/261430877): Finalise the decision on which admins to send the updates to.
- private <V> void sendPolicyChangedToAdmins(
+ private <V> void sendPolicyChangedToAdminsLocked(
PolicyState<V> policyState,
EnforcingAdmin callingAdmin,
PolicyDefinition<V> policyDefinition,
@@ -1210,17 +1213,19 @@
if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) {
return;
}
- if (!mLocalPolicies.contains(parentInfo.getUserHandle().getIdentifier())) {
- return;
- }
- for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
- parentInfo.getUserHandle().getIdentifier()).entrySet()) {
- enforcePolicyOnUser(userId, entry.getValue());
+ synchronized (mLock) {
+ if (!mLocalPolicies.contains(parentInfo.getUserHandle().getIdentifier())) {
+ return;
+ }
+ for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
+ parentInfo.getUserHandle().getIdentifier()).entrySet()) {
+ enforcePolicyOnUserLocked(userId, entry.getValue());
+ }
}
});
}
- private <V> void enforcePolicyOnUser(int userId, PolicyState<V> policyState) {
+ private <V> void enforcePolicyOnUserLocked(int userId, PolicyState<V> policyState) {
if (!policyState.getPolicyDefinition().isInheritable()) {
return;
}
@@ -1239,26 +1244,28 @@
*/
@NonNull
DevicePolicyState getDevicePolicyState() {
- Map<UserHandle, Map<PolicyKey, android.app.admin.PolicyState<?>>> policies =
- new HashMap<>();
- for (int i = 0; i < mLocalPolicies.size(); i++) {
- UserHandle user = UserHandle.of(mLocalPolicies.keyAt(i));
- policies.put(user, new HashMap<>());
- for (PolicyKey policyKey : mLocalPolicies.valueAt(i).keySet()) {
- policies.get(user).put(
- policyKey,
- mLocalPolicies.valueAt(i).get(policyKey).getParcelablePolicyState());
+ synchronized (mLock) {
+ Map<UserHandle, Map<PolicyKey, android.app.admin.PolicyState<?>>> policies =
+ new HashMap<>();
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ UserHandle user = UserHandle.of(mLocalPolicies.keyAt(i));
+ policies.put(user, new HashMap<>());
+ for (PolicyKey policyKey : mLocalPolicies.valueAt(i).keySet()) {
+ policies.get(user).put(
+ policyKey,
+ mLocalPolicies.valueAt(i).get(policyKey).getParcelablePolicyState());
+ }
}
- }
- if (!mGlobalPolicies.isEmpty()) {
- policies.put(UserHandle.ALL, new HashMap<>());
- for (PolicyKey policyKey : mGlobalPolicies.keySet()) {
- policies.get(UserHandle.ALL).put(
- policyKey,
- mGlobalPolicies.get(policyKey).getParcelablePolicyState());
+ if (!mGlobalPolicies.isEmpty()) {
+ policies.put(UserHandle.ALL, new HashMap<>());
+ for (PolicyKey policyKey : mGlobalPolicies.keySet()) {
+ policies.get(UserHandle.ALL).put(
+ policyKey,
+ mGlobalPolicies.get(policyKey).getParcelablePolicyState());
+ }
}
+ return new DevicePolicyState(policies);
}
- return new DevicePolicyState(policies);
}
@@ -1266,23 +1273,25 @@
* Removes all local and global policies set by that admin.
*/
void removePoliciesForAdmin(EnforcingAdmin admin) {
- Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
- for (PolicyKey policy : globalPolicies) {
- PolicyState<?> policyState = mGlobalPolicies.get(policy);
- if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
- removeGlobalPolicy(policyState.getPolicyDefinition(), admin);
- }
- }
-
- for (int i = 0; i < mLocalPolicies.size(); i++) {
- Set<PolicyKey> localPolicies = new HashSet<>(
- mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet());
- for (PolicyKey policy : localPolicies) {
- PolicyState<?> policyState = mLocalPolicies.get(
- mLocalPolicies.keyAt(i)).get(policy);
+ synchronized (mLock) {
+ Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
+ for (PolicyKey policy : globalPolicies) {
+ PolicyState<?> policyState = mGlobalPolicies.get(policy);
if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
- removeLocalPolicy(
- policyState.getPolicyDefinition(), admin, mLocalPolicies.keyAt(i));
+ removeGlobalPolicy(policyState.getPolicyDefinition(), admin);
+ }
+ }
+
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ Set<PolicyKey> localPolicies = new HashSet<>(
+ mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet());
+ for (PolicyKey policy : localPolicies) {
+ PolicyState<?> policyState = mLocalPolicies.get(
+ mLocalPolicies.keyAt(i)).get(policy);
+ if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
+ removeLocalPolicy(
+ policyState.getPolicyDefinition(), admin, mLocalPolicies.keyAt(i));
+ }
}
}
}
@@ -1292,23 +1301,25 @@
* Removes all local policies for the provided {@code userId}.
*/
private void removeLocalPoliciesForUser(int userId) {
- if (!mLocalPolicies.contains(userId)) {
- // No policies on user
- return;
- }
-
- Set<PolicyKey> localPolicies = new HashSet<>(mLocalPolicies.get(userId).keySet());
- for (PolicyKey policy : localPolicies) {
- PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
- Set<EnforcingAdmin> admins = new HashSet<>(
- policyState.getPoliciesSetByAdmins().keySet());
- for (EnforcingAdmin admin : admins) {
- removeLocalPolicy(
- policyState.getPolicyDefinition(), admin, userId);
+ synchronized (mLock) {
+ if (!mLocalPolicies.contains(userId)) {
+ // No policies on user
+ return;
}
- }
- mLocalPolicies.remove(userId);
+ Set<PolicyKey> localPolicies = new HashSet<>(mLocalPolicies.get(userId).keySet());
+ for (PolicyKey policy : localPolicies) {
+ PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ Set<EnforcingAdmin> admins = new HashSet<>(
+ policyState.getPoliciesSetByAdmins().keySet());
+ for (EnforcingAdmin admin : admins) {
+ removeLocalPolicy(
+ policyState.getPolicyDefinition(), admin, userId);
+ }
+ }
+
+ mLocalPolicies.remove(userId);
+ }
}
/**
@@ -1376,7 +1387,7 @@
*/
private void updateDeviceAdminServiceOnPolicyRemoveLocked(
@NonNull EnforcingAdmin enforcingAdmin) {
- if (doesAdminHavePolicies(enforcingAdmin)) {
+ if (doesAdminHavePoliciesLocked(enforcingAdmin)) {
return;
}
int userId = enforcingAdmin.getUserId();
@@ -1399,7 +1410,7 @@
/* actionForLog= */ "policy-removed");
}
- private boolean doesAdminHavePolicies(@NonNull EnforcingAdmin enforcingAdmin) {
+ private boolean doesAdminHavePoliciesLocked(@NonNull EnforcingAdmin enforcingAdmin) {
for (PolicyKey policy : mGlobalPolicies.keySet()) {
PolicyState<?> policyState = mGlobalPolicies.get(policy);
if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
@@ -1420,13 +1431,17 @@
@NonNull
private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) {
- return mEnforcingAdmins.contains(userId)
- ? mEnforcingAdmins.get(userId) : Collections.emptySet();
+ synchronized (mLock) {
+ return mEnforcingAdmins.contains(userId)
+ ? mEnforcingAdmins.get(userId) : Collections.emptySet();
+ }
}
private void write() {
- Log.d(TAG, "Writing device policies to file.");
- new DevicePoliciesReaderWriter().writeToFileLocked();
+ synchronized (mLock) {
+ Log.d(TAG, "Writing device policies to file.");
+ new DevicePoliciesReaderWriter().writeToFileLocked();
+ }
}
// TODO(b/256852787): trigger resolving logic after loading policies as roles are recalculated
@@ -1436,11 +1451,11 @@
synchronized (mLock) {
clear();
new DevicePoliciesReaderWriter().readFromFileLocked();
- reapplyAllPolicies();
+ reapplyAllPoliciesLocked();
}
}
- private <V> void reapplyAllPolicies() {
+ private <V> void reapplyAllPoliciesLocked() {
for (PolicyKey policy : mGlobalPolicies.keySet()) {
PolicyState<?> policyState = mGlobalPolicies.get(policy);
// Policy definition and value will always be of the same type
@@ -1470,10 +1485,8 @@
* <p>Note that this doesn't clear any enforcements, it only clears the data structures.
*/
void clearAllPolicies() {
- synchronized (mLock) {
- clear();
- write();
- }
+ clear();
+ write();
}
private void clear() {
synchronized (mLock) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3453e2b..a452328 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1413,7 +1413,6 @@
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
pushActiveAdminPackagesLocked(userHandle);
- pushMeteredDisabledPackages(userHandle);
}
}
} catch (RemoteException re) {
@@ -1454,6 +1453,7 @@
if (removedAdmin) {
// The removed admin might have disabled camera, so update user restrictions.
pushUserRestrictions(userHandle);
+ pushMeteredDisabledPackages(userHandle);
}
}
@@ -2093,7 +2093,8 @@
mUserData = new SparseArray<>();
mOwners = makeOwners(injector, pathProvider);
- mDevicePolicyEngine = new DevicePolicyEngine(mContext, mDeviceAdminServiceController);
+ mDevicePolicyEngine = new DevicePolicyEngine(
+ mContext, mDeviceAdminServiceController, getLockObject());
if (!mHasFeature) {
// Skip the rest of the initialization
@@ -7844,27 +7845,29 @@
throw new SecurityException("Cannot wipe data. " + restriction
+ " restriction is set for user " + userId);
}
+ });
- boolean isSystemUser = userId == UserHandle.USER_SYSTEM;
- boolean wipeDevice;
- if (factoryReset == null || !mInjector.isChangeEnabled(EXPLICIT_WIPE_BEHAVIOUR,
- adminPackage,
- userId)) {
- // Legacy mode
- wipeDevice = isSystemUser;
+ boolean isSystemUser = userId == UserHandle.USER_SYSTEM;
+ boolean wipeDevice;
+ if (factoryReset == null || !mInjector.isChangeEnabled(EXPLICIT_WIPE_BEHAVIOUR,
+ adminPackage,
+ userId)) {
+ // Legacy mode
+ wipeDevice = isSystemUser;
+ } else {
+ // Explicit behaviour
+ if (factoryReset) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
+ /*admin=*/ null,
+ /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MASTER_CLEAR},
+ USES_POLICY_WIPE_DATA,
+ adminPackage,
+ factoryReset ? UserHandle.USER_ALL :
+ getAffectedUser(calledOnParentInstance));
+ wipeDevice = true;
} else {
- // Explicit behaviour
- if (factoryReset) {
- EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
- /*admin=*/ null,
- /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA,
- MASTER_CLEAR},
- USES_POLICY_WIPE_DATA,
- adminPackage,
- factoryReset ? UserHandle.USER_ALL :
- getAffectedUser(calledOnParentInstance));
- wipeDevice = true;
- } else {
+ mInjector.binderWithCleanCallingIdentity(() -> {
Preconditions.checkCallAuthorization(!isSystemUser,
"User %s is a system user and cannot be removed", userId);
boolean isLastNonHeadlessUser = getUserInfo(userId).isFull()
@@ -7875,9 +7878,11 @@
"Removing user %s would leave the device without any active users. "
+ "Consider factory resetting the device instead.",
userId);
- wipeDevice = false;
- }
+ });
+ wipeDevice = false;
}
+ }
+ mInjector.binderWithCleanCallingIdentity(() -> {
if (wipeDevice) {
forceWipeDeviceNoLock(
(flags & WIPE_EXTERNAL_STORAGE) != 0,
@@ -13597,6 +13602,9 @@
: SecurityLog.TAG_USER_RESTRICTION_REMOVED;
SecurityLog.writeEvent(eventTag, caller.getPackageName(), caller.getUserId(), key);
}
+
+ Slogf.i(LOG_TAG, "Changing user restriction %s to: %b caller: %s",
+ key, enabled, caller.toString());
}
private void saveUserRestrictionsLocked(int userId) {
@@ -17882,41 +17890,44 @@
if (!mHasFeature) {
return packageNames;
}
- synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
- return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
- caller.getUserId(), packageNames);
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
+ caller.getUserId(), packageNames);
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
admin.meteredDisabledPackages = packageNames;
- pushMeteredDisabledPackages(caller.getUserId());
saveSettingsLocked(caller.getUserId());
- return excludedPkgs;
- });
- }
+ }
+ pushMeteredDisabledPackages(caller.getUserId());
+ return excludedPkgs;
+ });
}
private List<String> removeInvalidPkgsForMeteredDataRestriction(
int userId, List<String> pkgNames) {
- final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId);
- final List<String> excludedPkgs = new ArrayList<>();
- for (int i = pkgNames.size() - 1; i >= 0; --i) {
- final String pkgName = pkgNames.get(i);
- // If the package is an active admin, don't restrict it.
- if (activeAdmins.contains(pkgName)) {
- excludedPkgs.add(pkgName);
- continue;
- }
- // If the package doesn't exist, don't restrict it.
- try {
- if (!mInjector.getIPackageManager().isPackageAvailable(pkgName, userId)) {
+ synchronized (getLockObject()) {
+ final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId);
+ final List<String> excludedPkgs = new ArrayList<>();
+ for (int i = pkgNames.size() - 1; i >= 0; --i) {
+ final String pkgName = pkgNames.get(i);
+ // If the package is an active admin, don't restrict it.
+ if (activeAdmins.contains(pkgName)) {
excludedPkgs.add(pkgName);
+ continue;
}
- } catch (RemoteException e) {
- // Should not happen
+ // If the package doesn't exist, don't restrict it.
+ try {
+ if (!mInjector.getIPackageManager().isPackageAvailable(pkgName, userId)) {
+ excludedPkgs.add(pkgName);
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
}
+ pkgNames.removeAll(excludedPkgs);
+ return excludedPkgs;
}
- pkgNames.removeAll(excludedPkgs);
- return excludedPkgs;
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 70f0cbd..31efcca 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1938,10 +1938,11 @@
}
// Search UI manager service
- // TODO: add deviceHasConfigString(context, R.string.config_defaultSearchUiService)
- t.traceBegin("StartSearchUiService");
- mSystemServiceManager.startService(SEARCH_UI_MANAGER_SERVICE_CLASS);
- t.traceEnd();
+ if (deviceHasConfigString(context, R.string.config_defaultSearchUiService)) {
+ t.traceBegin("StartSearchUiService");
+ mSystemServiceManager.startService(SEARCH_UI_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+ }
// Smartspace manager service
// TODO: add deviceHasConfigString(context, R.string.config_defaultSmartspaceService)
@@ -2194,12 +2195,13 @@
}
// WallpaperEffectsGeneration manager service
- // TODO (b/135218095): Use deviceHasConfigString(context,
- // R.string.config_defaultWallpaperEffectsGenerationService)
- t.traceBegin("StartWallpaperEffectsGenerationService");
- mSystemServiceManager.startService(
+ if (deviceHasConfigString(context,
+ R.string.config_defaultWallpaperEffectsGenerationService)) {
+ t.traceBegin("StartWallpaperEffectsGenerationService");
+ mSystemServiceManager.startService(
WALLPAPER_EFFECTS_GENERATION_MANAGER_SERVICE_CLASS);
- t.traceEnd();
+ t.traceEnd();
+ }
t.traceBegin("StartAudioService");
if (!isArc) {
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index 0927c7a..c1d137f 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -130,17 +130,6 @@
}
} as IndexedMap<String, IndexedListSet<String>>
- fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
- getState {
- with(policy) { getDecision(subject, `object`) }
- }
-
- fun setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
- mutateState {
- with(policy) { setDecision(subject, `object`, decision) }
- }
- }
-
internal fun onUserAdded(userId: Int) {
mutateState {
with(policy) { onUserAdded(userId) }
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 44a29e5..c60f184 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -56,13 +56,6 @@
"Scheme policy for $subjectScheme and $objectScheme does not exist"
}
- fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int =
- with(getSchemePolicy(subject, `object`)) { getDecision(subject, `object`) }
-
- fun MutateStateScope.setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
- with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
- }
-
fun initialize(
state: MutableAccessState,
userIds: IntSet,
@@ -494,14 +487,6 @@
abstract val objectScheme: String
- abstract fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int
-
- abstract fun MutateStateScope.setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int
- )
-
open fun GetStateScope.onStateMutated() {}
open fun MutateStateScope.onInitialized() {}
diff --git a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
index 4b4f726..c02fe4d 100644
--- a/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/AppIdAppOpPolicy.kt
@@ -17,8 +17,6 @@
package com.android.server.permission.access.appop
import android.app.AppOpsManager
-import com.android.server.permission.access.AccessUri
-import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutableAccessState
import com.android.server.permission.access.MutateStateScope
@@ -40,22 +38,6 @@
override val subjectScheme: String
get() = UidUri.SCHEME
- override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
- subject as UidUri
- `object` as AppOpUri
- return getAppOpMode(subject.appId, subject.userId, `object`.appOpName)
- }
-
- override fun MutateStateScope.setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int
- ) {
- subject as UidUri
- `object` as AppOpUri
- setAppOpMode(subject.appId, subject.userId, `object`.appOpName, decision)
- }
-
override fun GetStateScope.onStateMutated() {
onAppOpModeChangedListeners.forEachIndexed { _, it -> it.onStateMutated() }
}
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index d384133..5398a57 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -17,8 +17,6 @@
package com.android.server.permission.access.appop
import android.app.AppOpsManager
-import com.android.server.permission.access.AccessUri
-import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutableAccessState
import com.android.server.permission.access.MutateStateScope
@@ -40,22 +38,6 @@
override val subjectScheme: String
get() = PackageUri.SCHEME
- override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
- subject as PackageUri
- `object` as AppOpUri
- return getAppOpMode(subject.packageName, subject.userId, `object`.appOpName)
- }
-
- override fun MutateStateScope.setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int
- ) {
- subject as PackageUri
- `object` as AppOpUri
- setAppOpMode(subject.packageName, subject.userId, `object`.appOpName, decision)
- }
-
override fun GetStateScope.onStateMutated() {
onAppOpModeChangedListeners.forEachIndexed { _, it -> it.onStateMutated() }
}
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
index 85326c3..dc9bae3 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedListExtensions.kt
@@ -64,6 +64,18 @@
operator fun <T> IndexedList<T>.plus(element: T): MutableIndexedList<T> =
toMutable().apply { this += element }
+// Using Int instead of <R> to avoid autoboxing, since we only have the use case for Int.
+inline fun <T> IndexedList<T>.reduceIndexed(
+ initialValue: Int,
+ accumulator: (Int, Int, T) -> Int
+): Int {
+ var value = initialValue
+ forEachIndexed { index, element ->
+ value = accumulator(value, index, element)
+ }
+ return value
+}
+
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableIndexedList<T>.minusAssign(element: T) {
remove(element)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
index 950d9aa..13fc141 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedListSetExtensions.kt
@@ -64,6 +64,18 @@
operator fun <T> IndexedListSet<T>.plus(element: T): MutableIndexedListSet<T> =
toMutable().apply { this += element }
+// Using Int instead of <R> to avoid autoboxing, since we only have the use case for Int.
+inline fun <T> IndexedListSet<T>.reduceIndexed(
+ initialValue: Int,
+ accumulator: (Int, Int, T) -> Int
+): Int {
+ var value = initialValue
+ forEachIndexed { index, element ->
+ value = accumulator(value, index, element)
+ }
+ return value
+}
+
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableIndexedListSet<T>.minusAssign(element: T) {
remove(element)
diff --git a/services/permission/java/com/android/server/permission/access/immutable/IndexedSetExtensions.kt b/services/permission/java/com/android/server/permission/access/immutable/IndexedSetExtensions.kt
index 2cc1b2a..5959ec6 100644
--- a/services/permission/java/com/android/server/permission/access/immutable/IndexedSetExtensions.kt
+++ b/services/permission/java/com/android/server/permission/access/immutable/IndexedSetExtensions.kt
@@ -80,6 +80,6 @@
add(element)
}
-operator fun <T> MutableIndexedSet<T>.plusAssign(list: List<T>) {
- list.forEachIndexed { _, it -> this += it }
+operator fun <T> MutableIndexedSet<T>.plusAssign(collection: Collection<T>) {
+ collection.forEach { this += it }
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
index fffc703..2c8175b 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPersistence.kt
@@ -74,8 +74,8 @@
if (packageName !in externalState.packageStates &&
packageName !in externalState.disabledSystemPackageStates) {
Slog.w(
- LOG_TAG,
- "Dropping permission with unknown package $packageName when parsing permissions"
+ LOG_TAG, "Dropping permission ${permission.name} from unknown package" +
+ " $packageName when parsing permissions"
)
permissions.removeAt(permissionIndex)
systemState.requestWriteMode(WriteMode.ASYNCHRONOUS)
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 9610188e..b0a964a 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
@@ -27,7 +27,6 @@
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutableAccessState
import com.android.server.permission.access.MutateStateScope
@@ -67,22 +66,6 @@
override val objectScheme: String
get() = PermissionUri.SCHEME
- override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
- subject as UidUri
- `object` as PermissionUri
- return getPermissionFlags(subject.appId, subject.userId, `object`.permissionName)
- }
-
- override fun MutateStateScope.setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int
- ) {
- subject as UidUri
- `object` as PermissionUri
- setPermissionFlags(subject.appId, subject.userId, `object`.permissionName, decision)
- }
-
override fun GetStateScope.onStateMutated() {
onPermissionFlagsChangedListeners.forEachIndexed { _, it -> it.onStateMutated() }
}
@@ -216,16 +199,17 @@
}
val androidPackage = packageState.androidPackage ?: return
val appId = packageState.appId
- androidPackage.requestedPermissions.forEachIndexed { _, permissionName ->
+ androidPackage.requestedPermissions.forEach { permissionName ->
val permission = newState.systemState.permissions[permissionName]
- ?: return@forEachIndexed
+ ?: return@forEach
if (!permission.isHardOrSoftRestricted) {
- return@forEachIndexed
+ return@forEach
}
- val isRequestedBySystemPackage =
- anyRequestingPackageInAppId(appId, permissionName) { it.isSystem }
+ val isRequestedBySystemPackage = anyPackageInAppId(appId) {
+ it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
+ }
if (isRequestedBySystemPackage) {
- return@forEachIndexed
+ return@forEach
}
val oldFlags = getPermissionFlags(appId, userId, permissionName)
var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT
@@ -258,21 +242,22 @@
val packageState = newState.externalState.packageStates[packageName] ?: return
val androidPackage = packageState.androidPackage ?: return
val appId = packageState.appId
- androidPackage.requestedPermissions.forEachIndexed { _, permissionName ->
+ androidPackage.requestedPermissions.forEach { permissionName ->
val permission = newState.systemState.permissions[permissionName]
- ?: return@forEachIndexed
+ ?: return@forEach
if (permission.isRemoved) {
- return@forEachIndexed
+ return@forEach
}
- val isRequestedByOtherPackages = anyRequestingPackageInAppId(appId, permissionName) {
- it.packageName != packageName
+ val isRequestedByOtherPackages = anyPackageInAppId(appId) {
+ it.packageName != packageName &&
+ permissionName in it.androidPackage!!.requestedPermissions
}
if (isRequestedByOtherPackages) {
- return@forEachIndexed
+ return@forEach
}
val oldFlags = getPermissionFlags(appId, userId, permissionName)
if (oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)) {
- return@forEachIndexed
+ return@forEach
}
var newFlags = oldFlags
newFlags = if (
@@ -444,7 +429,7 @@
// It's a config permission and has no owner, take ownership now.
oldPermission.copy(
permissionInfo = newPermissionInfo, isReconciled = true,
- appId = packageState.appId
+ type = Permission.TYPE_MANIFEST, appId = packageState.appId
)
} else if (newState.externalState.packageStates[oldPackageName]?.isSystem != true) {
Slog.w(
@@ -478,11 +463,12 @@
val isPermissionGroupChanged = newPermissionInfo.isRuntime &&
newPermissionInfo.group != null &&
newPermissionInfo.group != oldPermission.groupName
- val isPermissionTypeChanged = oldPermission.type != Permission.TYPE_CONFIG && (
- (newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
- (newPermissionInfo.isInternal && !oldPermission.isInternal)
- )
- if (isPermissionGroupChanged || isPermissionTypeChanged) {
+ val isPermissionProtectionChanged =
+ oldPermission.type != Permission.TYPE_CONFIG && (
+ (newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
+ (newPermissionInfo.isInternal && !oldPermission.isInternal)
+ )
+ if (isPermissionGroupChanged || isPermissionProtectionChanged) {
newState.externalState.userIds.forEachIndexed { _, userId ->
newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
if (isPermissionGroupChanged) {
@@ -497,11 +483,11 @@
" to ${newPermissionInfo.group}"
)
}
- if (isPermissionTypeChanged) {
+ if (isPermissionProtectionChanged) {
Slog.w(
LOG_TAG, "Revoking permission $permissionName for" +
" appId $appId and userId $userId as the permission" +
- " type changed."
+ " protection changed."
)
}
setPermissionFlags(appId, userId, permissionName, 0)
@@ -517,7 +503,7 @@
if (oldPermission != null) {
oldPermission.copy(
permissionInfo = newPermissionInfo, isReconciled = true,
- appId = packageState.appId
+ type = Permission.TYPE_MANIFEST, appId = packageState.appId
)
} else {
Permission(
@@ -530,8 +516,17 @@
newState.mutateSystemState().mutatePermissionTrees()[permissionName] = newPermission
} else {
newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
+ val isPermissionChanged = oldPermission == null ||
+ newPackageName != oldPermission.packageName ||
+ newPermission.protectionLevel != oldPermission.protectionLevel || (
+ oldPermission.isReconciled && newPermission.isRuntime &&
+ newPermission.groupName != null &&
+ newPermission.groupName != oldPermission.groupName
+ )
+ if (isPermissionChanged) {
+ changedPermissionNames += permissionName
+ }
}
- changedPermissionNames += permissionName
}
}
@@ -628,36 +623,59 @@
}
private fun MutateStateScope.revokePermissionsOnPackageUpdate(appId: Int) {
+ val hasOldPackage = appId in oldState.externalState.appIdPackageNames &&
+ anyPackageInAppId(appId, oldState) { true }
+ if (!hasOldPackage) {
+ // Don't revoke anything if this isn't a package update, i.e. if information about the
+ // old package isn't available. Notably, this also means skipping packages changed via
+ // OTA, but the revocation here is also mostly for normal apps and there's no way to get
+ // information about the package before OTA anyway.
+ return
+ }
+
// If the app is updated, and has scoped storage permissions, then it is possible that the
// app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
- newState.userStates.forEachIndexed { _, userId, userState ->
- userState.appIdPermissionFlags[appId]?.forEachReversedIndexed {
- _, permissionName, oldFlags ->
- if (permissionName !in STORAGE_AND_MEDIA_PERMISSIONS || oldFlags == 0) {
- return@forEachReversedIndexed
- }
- val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, oldState)
- val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, newState)
- val isTargetSdkVersionDowngraded = oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
- newTargetSdkVersion < Build.VERSION_CODES.Q
- val isTargetSdkVersionUpgraded = oldTargetSdkVersion < Build.VERSION_CODES.Q &&
- newTargetSdkVersion >= Build.VERSION_CODES.Q
- val oldIsRequestLegacyExternalStorage = anyRequestingPackageInAppId(
- appId, permissionName, oldState
- ) { it.androidPackage!!.isRequestLegacyExternalStorage }
- val newIsRequestLegacyExternalStorage = anyRequestingPackageInAppId(
- appId, permissionName, newState
- ) { it.androidPackage!!.isRequestLegacyExternalStorage }
- val isNewlyRequestingLegacyExternalStorage = !isTargetSdkVersionUpgraded &&
- !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
- if ((isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded) &&
- oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED)) {
- Slog.v(LOG_TAG, "Revoking storage permission: $permissionName for appId: " +
- " $appId and user: $userId")
- val newFlags = oldFlags andInv (
- PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
- )
- setPermissionFlags(appId, userId, permissionName, newFlags)
+ val oldTargetSdkVersion =
+ reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
+ targetSdkVersion, packageState ->
+ targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
+ }
+ val newTargetSdkVersion =
+ reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
+ targetSdkVersion, packageState ->
+ targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
+ }
+ @Suppress("ConvertTwoComparisonsToRangeCheck")
+ val isTargetSdkVersionDowngraded = oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
+ newTargetSdkVersion < Build.VERSION_CODES.Q
+ @Suppress("ConvertTwoComparisonsToRangeCheck")
+ val isTargetSdkVersionUpgraded = oldTargetSdkVersion < Build.VERSION_CODES.Q &&
+ newTargetSdkVersion >= Build.VERSION_CODES.Q
+ val oldIsRequestLegacyExternalStorage = anyPackageInAppId(appId, oldState) {
+ it.androidPackage!!.isRequestLegacyExternalStorage
+ }
+ val newIsRequestLegacyExternalStorage = anyPackageInAppId(appId, newState) {
+ it.androidPackage!!.isRequestLegacyExternalStorage
+ }
+ val isNewlyRequestingLegacyExternalStorage = !isTargetSdkVersionUpgraded &&
+ !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
+ val shouldRevokeStorageAndMediaPermissions = isNewlyRequestingLegacyExternalStorage ||
+ isTargetSdkVersionDowngraded
+ if (shouldRevokeStorageAndMediaPermissions) {
+ newState.userStates.forEachIndexed { _, userId, userState ->
+ userState.appIdPermissionFlags[appId]?.forEachReversedIndexed {
+ _, permissionName, oldFlags ->
+ if (permissionName in STORAGE_AND_MEDIA_PERMISSIONS &&
+ oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED)) {
+ Slog.v(
+ LOG_TAG, "Revoking storage permission: $permissionName for appId: " +
+ " $appId and user: $userId"
+ )
+ val newFlags = oldFlags andInv (
+ PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
+ )
+ setPermissionFlags(appId, userId, permissionName, newFlags)
+ }
}
}
}
@@ -670,8 +688,9 @@
val externalState = newState.externalState
externalState.userIds.forEachIndexed { _, userId ->
externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
- val isPermissionRequested =
- anyRequestingPackageInAppId(appId, permissionName) { true }
+ val isPermissionRequested = anyPackageInAppId(appId) {
+ permissionName in it.androidPackage!!.requestedPermissions
+ }
if (isPermissionRequested) {
evaluatePermissionState(appId, userId, permissionName, installedPackageState)
}
@@ -695,7 +714,7 @@
userId: Int,
installedPackageState: PackageState?
) {
- packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
+ packageState.androidPackage?.requestedPermissions?.forEach { permissionName ->
evaluatePermissionState(
packageState.appId, userId, permissionName, installedPackageState
)
@@ -709,8 +728,21 @@
installedPackageState: PackageState?
) {
val packageNames = newState.externalState.appIdPackageNames[appId]!!
- val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
- newState.externalState.packageStates[packageName]!!.androidPackage == null
+ // Repeatedly checking whether a permission is requested can actually be costly, so we cache
+ // the result for this method which is frequently called during boot, instead of calling
+ // anyPackageInAppId() and checking requested permissions multiple times.
+ val requestingPackageStates = MutableIndexedList<PackageState>()
+ var hasMissingPackage = false
+ packageNames.forEachIndexed { _, packageName ->
+ val packageState = newState.externalState.packageStates[packageName]!!
+ val androidPackage = packageState.androidPackage
+ if (androidPackage != null) {
+ if (permissionName in androidPackage.requestedPermissions) {
+ requestingPackageStates += packageState
+ }
+ } else {
+ hasMissingPackage = true
+ }
}
if (packageNames.size == 1 && hasMissingPackage) {
// For non-shared-user packages with missing androidPackage, skip evaluation.
@@ -734,8 +766,8 @@
val isRequestedByInstalledPackage = installedPackageState != null &&
permissionName in installedPackageState.androidPackage!!.requestedPermissions
val isRequestedBySystemPackage =
- anyRequestingPackageInAppId(appId, permissionName) { it.isSystem }
- val isCompatibilityPermission = anyRequestingPackageInAppId(appId, permissionName) {
+ requestingPackageStates.anyIndexed { _, it -> it.isSystem }
+ val isCompatibilityPermission = requestingPackageStates.anyIndexed { _, it ->
isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
}
// If this is an existing, non-system package,
@@ -760,20 +792,17 @@
// Keep the non-runtime permission grants for shared UID with missing androidPackage
PermissionFlags.PROTECTION_GRANTED
} else {
- val mayGrantByPrivileged = !permission.isPrivileged || (
- anyRequestingPackageInAppId(appId, permissionName) {
+ val mayGrantByPrivileged = !permission.isPrivileged ||
+ requestingPackageStates.anyIndexed { _, it ->
checkPrivilegedPermissionAllowlist(it, permission)
}
- )
- val shouldGrantBySignature = permission.isSignature && (
- anyRequestingPackageInAppId(appId, permissionName) {
+ val shouldGrantBySignature = permission.isSignature &&
+ requestingPackageStates.anyIndexed { _, it ->
shouldGrantPermissionBySignature(it, permission)
}
- )
- val shouldGrantByProtectionFlags =
- anyRequestingPackageInAppId(appId, permissionName) {
- shouldGrantPermissionByProtectionFlags(it, permission)
- }
+ val shouldGrantByProtectionFlags = requestingPackageStates.anyIndexed { _, it ->
+ shouldGrantPermissionByProtectionFlags(it, permission)
+ }
if (mayGrantByPrivileged &&
(shouldGrantBySignature || shouldGrantByProtectionFlags)) {
PermissionFlags.PROTECTION_GRANTED
@@ -803,7 +832,12 @@
} else if (permission.isRuntime) {
var newFlags = oldFlags and PermissionFlags.MASK_RUNTIME
val wasRevoked = newFlags != 0 && !PermissionFlags.isPermissionGranted(newFlags)
- if (getAppIdTargetSdkVersion(appId, permissionName) < Build.VERSION_CODES.M) {
+ val targetSdkVersion =
+ requestingPackageStates.reduceIndexed(Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ targetSdkVersion, _, packageState ->
+ targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
+ }
+ if (targetSdkVersion < Build.VERSION_CODES.M) {
if (permission.isRuntimeOnly) {
// Different from the old implementation, which simply skips a runtime-only
// permission, we now only allow holding on to the restriction related flags,
@@ -835,7 +869,7 @@
val wasGrantedByImplicit = newFlags.hasBits(PermissionFlags.IMPLICIT_GRANTED)
val isLeanbackNotificationsPermission = newState.externalState.isLeanback &&
permissionName in NOTIFICATIONS_PERMISSIONS
- val isImplicitPermission = anyRequestingPackageInAppId(appId, permissionName) {
+ val isImplicitPermission = requestingPackageStates.anyIndexed { _, it ->
permissionName in it.androidPackage!!.implicitPermissions
}
val sourcePermissions = newState.externalState
@@ -1106,30 +1140,15 @@
}
}
- private fun MutateStateScope.getAppIdTargetSdkVersion(
+ private inline fun MutateStateScope.anyPackageInAppId(
appId: Int,
- permissionName: String,
- state: AccessState = newState
- ): Int {
- var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
- forEachRequestingPackageInAppId(appId, permissionName, state) {
- targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
- }
- return targetSdkVersion
- }
-
- private inline fun MutateStateScope.anyRequestingPackageInAppId(
- appId: Int,
- permissionName: String,
state: AccessState = newState,
predicate: (PackageState) -> Boolean
): Boolean {
val packageNames = state.externalState.appIdPackageNames[appId]!!
return packageNames.anyIndexed { _, packageName ->
val packageState = state.externalState.packageStates[packageName]!!
- val androidPackage = packageState.androidPackage
- androidPackage != null && permissionName in androidPackage.requestedPermissions &&
- predicate(packageState)
+ packageState.androidPackage != null && predicate(packageState)
}
}
@@ -1147,18 +1166,20 @@
}
}
- private inline fun MutateStateScope.forEachRequestingPackageInAppId(
+ // Using Int instead of <T> to avoid autoboxing, since we only have the use case for Int.
+ private inline fun MutateStateScope.reducePackageInAppId(
appId: Int,
- permissionName: String,
+ initialValue: Int,
state: AccessState = newState,
- action: (PackageState) -> Unit
- ) {
+ accumulator: (Int, PackageState) -> Int
+ ): Int {
val packageNames = state.externalState.appIdPackageNames[appId]!!
- packageNames.forEachIndexed { _, packageName ->
+ return packageNames.reduceIndexed(initialValue) { value, _, packageName ->
val packageState = state.externalState.packageStates[packageName]!!
- val androidPackage = packageState.androidPackage
- if (androidPackage != null && permissionName in androidPackage.requestedPermissions) {
- action(packageState)
+ if (packageState.androidPackage != null) {
+ accumulator(value, packageState)
+ } else {
+ value
}
}
}
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 82fe0a4..edacf188 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
@@ -2009,7 +2009,9 @@
}
override fun onUserCreated(userId: Int) {
- service.onUserAdded(userId)
+ withCorkedPackageInfoCache {
+ service.onUserAdded(userId)
+ }
}
override fun onUserRemoved(userId: Int) {
@@ -2024,7 +2026,9 @@
packageNames = storageVolumePackageNames.remove(volumeUuid) ?: emptyList()
mountedStorageVolumes += volumeUuid
}
- service.onStorageVolumeMounted(volumeUuid, packageNames, fingerprintChanged)
+ withCorkedPackageInfoCache {
+ service.onStorageVolumeMounted(volumeUuid, packageNames, fingerprintChanged)
+ }
}
override fun onPackageAdded(
@@ -2120,6 +2124,15 @@
}
}
+ private inline fun <T> withCorkedPackageInfoCache(block: () -> T): T {
+ PackageManager.corkPackageInfoCache()
+ try {
+ return block()
+ } finally {
+ PackageManager.uncorkPackageInfoCache()
+ }
+ }
+
/**
* Check whether a UID is root or system UID.
*/
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 774f62d..fd478dc 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -245,10 +246,13 @@
intent.putExtra(PrintManager.EXTRA_PRINT_JOB, printJob);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ ActivityOptions activityOptions = ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
IntentSender intentSender = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
- null, new UserHandle(mUserId)) .getIntentSender();
+ | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+ activityOptions.toBundle(), new UserHandle(mUserId)).getIntentSender();
Bundle result = new Bundle();
result.putParcelable(PrintManager.EXTRA_PRINT_JOB, printJob);
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
index 138b611..3683dca 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index ca4a404..dc92376 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -66,7 +66,6 @@
import android.test.AndroidTestCase;
import android.util.Log;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
@@ -2507,7 +2506,6 @@
}
@LargeTest
- @FlakyTest(bugId = 283797480)
public void testCheckSignaturesRotatedAgainstRotated() throws Exception {
// checkSignatures should be successful when both apps have been signed with the same
// rotated key since the initial signature comparison between the two apps should
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index c7fb32c..0eac4e6 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -231,8 +231,8 @@
assertSame(deserialized.getPackageName(), deserialized2.getPackageName());
assertSame(deserialized.getPermission(),
deserialized2.getPermission());
- assertSame(deserialized.getRequestedPermissions().get(0),
- deserialized2.getRequestedPermissions().get(0));
+ assertSame(deserialized.getRequestedPermissions().iterator().next(),
+ deserialized2.getRequestedPermissions().iterator().next());
List<String> protectedBroadcastsOne = new ArrayList<>(1);
protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts());
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 3200871..edab1d6 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -623,7 +623,6 @@
expect.that(after.longVersionCode).isEqualTo(38654705667)
expect.that(after.requestedPermissions)
.containsExactlyElementsIn(after.usesPermissions.map { it.name })
- .inOrder()
expect.that(after.mimeGroups).containsExactly(
"TestActivityName/mimeGroup",
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/affected_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/affected_cpus
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/affected_cpus
@@ -0,0 +1 @@
+
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/related_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/related_cpus
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/related_cpus
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_cur_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_cur_freq
new file mode 100644
index 0000000..dadd973
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+1230000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/scaling_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/stats/time_in_state b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/stats/time_in_state
new file mode 100644
index 0000000..5121f666
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy0/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2500000 100
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/affected_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/related_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/related_cpus
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/related_cpus
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_cur_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_cur_freq
new file mode 100644
index 0000000..2bc4ce9
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_cur_freq
@@ -0,0 +1 @@
+1450000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/scaling_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/stats/time_in_state b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/stats/time_in_state
new file mode 100644
index 0000000..7ed12cf
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_affected_cpus/policy1/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2800000 100
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/affected_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/affected_cpus
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/affected_cpus
@@ -0,0 +1 @@
+0
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/related_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/related_cpus
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/related_cpus
@@ -0,0 +1 @@
+
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_cur_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_cur_freq
new file mode 100644
index 0000000..dadd973
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+1230000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/scaling_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/stats/time_in_state b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/stats/time_in_state
new file mode 100644
index 0000000..5121f666
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy0/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2500000 100
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/affected_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/related_cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/related_cpus
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/related_cpus
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_cur_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_cur_freq
new file mode 100644
index 0000000..2bc4ce9
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_cur_freq
@@ -0,0 +1 @@
+1450000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/scaling_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/stats/time_in_state b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/stats/time_in_state
new file mode 100644
index 0000000..7ed12cf
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_empty_related_cpus/policy1/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2800000 100
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq
index a93d6f7..d17275f 100644
--- a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq
@@ -1 +1 @@
-2500000
+2600000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy1/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy1/scaling_max_freq
index c754f1a..79c41c7 100644
--- a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy1/scaling_max_freq
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy1/scaling_max_freq
@@ -1 +1 @@
-2800000
+2900000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq
index deebb18..526a717 100644
--- a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq
@@ -1 +1 @@
-2000000
+2100000
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/background/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/background/cpus
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/background/cpus
@@ -0,0 +1 @@
+
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/top-app/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/top-app/cpus
new file mode 100644
index 0000000..40c7bb2
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_with_empty_cpus/top-app/cpus
@@ -0,0 +1 @@
+0-3
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index a614c4d..2bc66ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -27,6 +27,7 @@
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.util.DebugUtils.valueToString;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -742,24 +743,24 @@
broadcastIntent(intent1, null, true);
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
- StickyBroadcast.create(intent1, false, Process.myUid()));
+ StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
assertNull(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER));
assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER));
broadcastIntent(intent2, options.toBundle(), true);
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
- StickyBroadcast.create(intent1, false, Process.myUid()));
+ StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER),
- StickyBroadcast.create(intent2, true, Process.myUid()));
+ StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN));
assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER));
broadcastIntent(intent3, null, true);
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER),
- StickyBroadcast.create(intent1, false, Process.myUid()));
+ StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER),
- StickyBroadcast.create(intent2, true, Process.myUid()));
+ StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN));
assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER),
- StickyBroadcast.create(intent3, false, Process.myUid()));
+ StickyBroadcast.create(intent3, false, Process.myUid(), PROCESS_STATE_UNKNOWN));
}
@SuppressWarnings("GuardedBy")
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 65f21f0..1542112 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED;
import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD;
@@ -246,7 +248,7 @@
return new BroadcastRecord(mImpl, intent, mProcess, PACKAGE_RED, null, 21, 42, false, null,
null, null, null, AppOpsManager.OP_NONE, options, receivers, null, resultTo,
Activity.RESULT_OK, null, null, ordered, false, false, UserHandle.USER_SYSTEM,
- BackgroundStartPrivileges.NONE, false, null);
+ BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN);
}
private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
@@ -1092,6 +1094,17 @@
verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
verifyPendingRecords(redQueue, List.of(screenOff));
verifyPendingRecords(blueQueue, List.of(screenOff, screenOn));
+
+ final BroadcastRecord screenOffRecord = makeBroadcastRecord(screenOff, screenOnOffOptions,
+ List.of(greenReceiver, redReceiver, blueReceiver), resultTo, false);
+ screenOffRecord.setDeliveryState(2, BroadcastRecord.DELIVERY_DEFERRED,
+ "testDeliveryGroupPolicy_resultTo_diffReceivers");
+ mImpl.enqueueBroadcastLocked(screenOffRecord);
+ mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
+ List.of(greenReceiver, blueReceiver), resultTo, false));
+ verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
+ verifyPendingRecords(redQueue, List.of(screenOff));
+ verifyPendingRecords(blueQueue, List.of(screenOn));
}
@Test
@@ -1277,6 +1290,36 @@
}
@Test
+ public void testDeliveryGroupPolicy_merged_multipleReceivers() {
+ final long now = SystemClock.elapsedRealtime();
+ final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast1 = createDropboxBroadcast(
+ "TAG_A", now, 2);
+ final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast2 = createDropboxBroadcast(
+ "TAG_A", now + 1000, 4);
+
+ mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast1.first,
+ dropboxEntryBroadcast1.second,
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
+ makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
+ false));
+ mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast2.first,
+ dropboxEntryBroadcast2.second,
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
+ makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
+ false));
+
+ final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+ final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
+ getUidForPackage(PACKAGE_RED));
+
+ verifyPendingRecords(greenQueue,
+ List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
+ verifyPendingRecords(redQueue,
+ List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
+ }
+
+ @Test
public void testDeliveryGroupPolicy_sameAction_differentMatchingCriteria() {
final Intent closeSystemDialogs1 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
final BroadcastOptions optionsCloseSystemDialog1 = BroadcastOptions.makeBasic()
@@ -1407,7 +1450,7 @@
eq(BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST),
eq(BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD),
anyLong(), anyLong(), anyLong(), anyInt(), nullable(String.class),
- anyString(), anyInt(), anyInt()),
+ anyString(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt()),
times(1));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 03231ec..0f75ea5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER;
import static android.os.UserHandle.USER_SYSTEM;
@@ -611,7 +612,7 @@
callerApp.getPid(), callerApp.info.uid, false, null, null, null, null,
AppOpsManager.OP_NONE, options, receivers, callerApp, resultTo,
Activity.RESULT_OK, null, resultExtras, ordered, false, false, userId,
- BackgroundStartPrivileges.NONE, false, null);
+ BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN);
}
private void assertHealth() {
@@ -1599,7 +1600,7 @@
null, null, null, null, AppOpsManager.OP_NONE, BroadcastOptions.makeBasic(),
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), null, null,
Activity.RESULT_OK, null, null, false, false, false, UserHandle.USER_SYSTEM,
- backgroundStartPrivileges, false, null);
+ backgroundStartPrivileges, false, null, PROCESS_STATE_UNKNOWN);
enqueueBroadcast(r);
waitForIdle();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index 08952ea..f0efb79 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.ACTION_LOCKED_BOOT_COMPLETED;
@@ -958,7 +959,8 @@
userId,
BackgroundStartPrivileges.NONE,
false /* timeoutExempt */,
- filterExtrasForReceiver);
+ filterExtrasForReceiver,
+ PROCESS_STATE_UNKNOWN);
}
private static int getAppId(int i) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 24bc57e..646f486 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -38,6 +38,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -54,6 +55,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -119,6 +121,8 @@
@Before
public void setUp() {
+ assumeFalse(PermissionManager.USE_ACCESS_CHECKING_SERVICE);
+
mStorageFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME);
mRecentAccessesFile = new File(sContext.getFilesDir(), APP_OPS_ACCESSES_FILENAME);
mStorageFile.delete();
@@ -138,6 +142,11 @@
@After
public void tearDown() {
+ // @After methods are still executed even if there's assumption failure in @Before.
+ if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
+ return;
+ }
+
mAppOpsService.shutdown();
mMockingSession.finishMocking();
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
index 04f6f8b..2fbe8aa 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
@@ -48,6 +48,11 @@
private static final String TAG = CpuInfoReaderTest.class.getSimpleName();
private static final String ROOT_DIR_NAME = "CpuInfoReaderTest";
private static final String VALID_CPUSET_DIR = "valid_cpuset";
+ private static final String VALID_CPUSET_WITH_EMPTY_CPUS = "valid_cpuset_with_empty_cpus";
+ private static final String VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS =
+ "valid_cpufreq_with_empty_affected_cpus";
+ private static final String VALID_CPUFREQ_WITH_EMPTY_RELATED_CPUS =
+ "valid_cpufreq_with_empty_related_cpus";
private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR =
"valid_cpufreq_with_time_in_state";
private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR =
@@ -142,8 +147,8 @@
expectedCpuInfos.clear();
expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
- /* normalizedAvailableCpuFreqKHz= */ 2_425_919,
+ /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
+ /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
/* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
@@ -152,8 +157,8 @@
/* guestNiceTimeMillis= */ 0)));
expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
- /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
- /* normalizedAvailableCpuFreqKHz= */ 2_403_009,
+ /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
+ /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
/* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
@@ -163,8 +168,8 @@
expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
/* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
- /* normalizedAvailableCpuFreqKHz= */ 1_688_209,
+ /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
+ /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
/* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
/* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
@@ -174,7 +179,7 @@
expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
/* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+ /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
/* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
/* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
@@ -403,6 +408,104 @@
}
@Test
+ public void testReadCpuInfoWithEmptyRelatedCpus() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_EMPTY_RELATED_CPUS),
+ getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
+
+ expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ compareCpuInfos("CPU infos with policy 0 containing an empty related_cpus file",
+ expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithEmptyCpusetCpus() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_WITH_EMPTY_CPUS),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
+ getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
+ expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
+ /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
+ /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
+ /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
+ /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
+ /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
+ /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
+ /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
+ /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
+ /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
+ /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
+ /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
+ /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
+ /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ compareCpuInfos("CPU infos with empty background cpu set", expectedCpuInfos,
+ actualCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithEmptyAffectedCpus() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS),
+ getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
+
+ expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
+ FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ compareCpuInfos("CPU infos with policy 0 containing an empty affected_cpus file",
+ expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
public void testReadCpuInfoWithEmptyProcStat() throws Exception {
File emptyFile = getCacheFile(EMPTY_FILE);
assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile())
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index ed68fb9..de5e6d7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -646,14 +646,16 @@
@Test
public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
DisplayPowerRequest dpr = new DisplayPowerRequest();
dpr.policy = DisplayPowerRequest.POLICY_DOZE;
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index c5ff8cc..dd23d9f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -28,6 +28,7 @@
import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sUptimeMillisClock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -148,6 +149,9 @@
// Used in JobConcurrencyManager.
doReturn(mock(UserManagerInternal.class))
.when(() -> LocalServices.getService(UserManagerInternal.class));
+ // Used in JobStatus.
+ doReturn(mock(JobSchedulerInternal.class))
+ .when(() -> LocalServices.getService(JobSchedulerInternal.class));
// Called via IdleController constructor.
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
when(mContext.getResources()).thenReturn(mock(Resources.class));
@@ -168,6 +172,8 @@
JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
JobSchedulerService.sElapsedRealtimeClock =
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ // Make sure the uptime is at least 24 hours so that tests that rely on high uptime work.
+ sUptimeMillisClock = getAdvancedClock(sUptimeMillisClock, 24 * HOUR_IN_MILLIS);
// Called by DeviceIdlenessTracker
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mock(UiModeManager.class));
@@ -313,6 +319,260 @@
}
@Test
+ public void testGetMinJobExecutionGuaranteeMs_timeoutSafeguards_disabled() {
+ JobStatus jobUij = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(1)
+ .setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ JobStatus jobEj = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(2).setExpedited(true));
+ JobStatus jobReg = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(3));
+ spyOn(jobUij);
+ when(jobUij.shouldTreatAsUserInitiatedJob()).thenReturn(true);
+ jobUij.startedAsUserInitiatedJob = true;
+ spyOn(jobEj);
+ when(jobEj.shouldTreatAsExpeditedJob()).thenReturn(true);
+ jobEj.startedAsExpeditedJob = true;
+
+ mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = false;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = 2;
+ mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
+
+ // Safeguards disabled -> no penalties.
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 UIJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 UIJ timeouts. Safeguards disabled -> no penalties.
+ jobUij.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 EJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 EJ timeouts. Safeguards disabled -> no penalties.
+ jobEj.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 reg timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 Reg timeouts. Safeguards disabled -> no penalties.
+ jobReg.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+ }
+
+ @Test
+ public void testGetMinJobExecutionGuaranteeMs_timeoutSafeguards_enabled() {
+ JobStatus jobUij = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(1)
+ .setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ JobStatus jobEj = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(2).setExpedited(true));
+ JobStatus jobReg = createJobStatus("testGetMinJobExecutionGuaranteeMs_timeoutSafeguards",
+ createJobInfo(3));
+ spyOn(jobUij);
+ when(jobUij.shouldTreatAsUserInitiatedJob()).thenReturn(true);
+ jobUij.startedAsUserInitiatedJob = true;
+ spyOn(jobEj);
+ when(jobEj.shouldTreatAsExpeditedJob()).thenReturn(true);
+ jobEj.startedAsExpeditedJob = true;
+
+ mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = true;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = 2;
+ mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
+
+ // No timeouts -> no penalties.
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 UIJ timeout. No execution penalty yet.
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // Not a timeout -> 1 UIJ timeout. No execution penalty yet.
+ jobUij.madeActive = sUptimeMillisClock.millis() - 1;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 UIJ timeouts. Min execution penalty only for UIJs.
+ jobUij.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 EJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 EJ timeouts. Max execution penalty for EJs.
+ jobEj.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 1 reg timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+
+ // 2 Reg timeouts. Max execution penalty for regular jobs.
+ jobReg.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobReg));
+ }
+
+ @Test
public void testGetMaxJobExecutionTimeMs() {
JobStatus jobUIDT = createJobStatus("testGetMaxJobExecutionTimeMs",
createJobInfo(10)
@@ -327,7 +587,7 @@
doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
.when(quotaController).getMaxJobExecutionTimeMsLocked(any());
doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
- .when(quotaController).getMaxJobExecutionTimeMsLocked(any());
+ .when(tareController).getMaxJobExecutionTimeMsLocked(any());
grantRunUserInitiatedJobsPermission(true);
assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
@@ -337,6 +597,306 @@
mService.getMaxJobExecutionTimeMs(jobUIDT));
}
+ @Test
+ public void testGetMaxJobExecutionTimeMs_timeoutSafeguards_disabled() {
+ JobStatus jobUij = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(1)
+ .setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ JobStatus jobEj = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(2).setExpedited(true));
+ JobStatus jobReg = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(3));
+ spyOn(jobUij);
+ when(jobUij.shouldTreatAsUserInitiatedJob()).thenReturn(true);
+ jobUij.startedAsUserInitiatedJob = true;
+ spyOn(jobEj);
+ when(jobEj.shouldTreatAsExpeditedJob()).thenReturn(true);
+ jobEj.startedAsExpeditedJob = true;
+
+ QuotaController quotaController = mService.getQuotaController();
+ spyOn(quotaController);
+ TareController tareController = mService.getTareController();
+ spyOn(tareController);
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(quotaController).getMaxJobExecutionTimeMsLocked(any());
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(tareController).getMaxJobExecutionTimeMsLocked(any());
+
+ mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = false;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = 2;
+ mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
+
+ // Safeguards disabled -> no penalties.
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 UIJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 UIJ timeouts. Safeguards disabled -> no penalties.
+ jobUij.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 EJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 EJ timeouts. Safeguards disabled -> no penalties.
+ jobEj.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 reg timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 Reg timeouts. Safeguards disabled -> no penalties.
+ jobReg.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+ }
+
+ @Test
+ public void testGetMaxJobExecutionTimeMs_timeoutSafeguards_enabled() {
+ JobStatus jobUij = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(1)
+ .setUserInitiated(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ JobStatus jobEj = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(2).setExpedited(true));
+ JobStatus jobReg = createJobStatus("testGetMaxJobExecutionTimeMs_timeoutSafeguards",
+ createJobInfo(3));
+ spyOn(jobUij);
+ when(jobUij.shouldTreatAsUserInitiatedJob()).thenReturn(true);
+ jobUij.startedAsUserInitiatedJob = true;
+ spyOn(jobEj);
+ when(jobEj.shouldTreatAsExpeditedJob()).thenReturn(true);
+ jobEj.startedAsExpeditedJob = true;
+
+ QuotaController quotaController = mService.getQuotaController();
+ spyOn(quotaController);
+ TareController tareController = mService.getTareController();
+ spyOn(tareController);
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(quotaController).getMaxJobExecutionTimeMsLocked(any());
+ doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
+ .when(tareController).getMaxJobExecutionTimeMsLocked(any());
+
+ mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = true;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_EJ_COUNT = 2;
+ mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_REG_COUNT = 2;
+ mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
+
+ // No timeouts -> no penalties.
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 UIJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // Not a timeout -> 1 UIJ timeout. No max execution penalty yet.
+ jobUij.madeActive = sUptimeMillisClock.millis() - 1;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 UIJ timeouts. Max execution penalty only for UIJs.
+ jobUij.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_UI_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobUij, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 EJ timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // Not a timeout -> 1 EJ timeout. No max execution penalty yet.
+ jobEj.madeActive = sUptimeMillisClock.millis() - 1;
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 EJ timeouts. Max execution penalty for EJs.
+ jobEj.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobEj, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 1 reg timeout. No max execution penalty yet.
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // Not a timeout -> 1 reg timeout. No max execution penalty yet.
+ jobReg.madeActive = sUptimeMillisClock.millis() - 1;
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+
+ // 2 Reg timeouts. Max execution penalty for regular jobs.
+ jobReg.madeActive =
+ sUptimeMillisClock.millis() - mService.mConstants.RUNTIME_MIN_GUARANTEE_MS;
+ mService.maybeProcessBuggyJob(jobReg, JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ grantRunUserInitiatedJobsPermission(true);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ grantRunUserInitiatedJobsPermission(false);
+ assertEquals(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mService.getMaxJobExecutionTimeMs(jobUij));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobEj));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMaxJobExecutionTimeMs(jobReg));
+ }
+
/**
* Confirm that
* {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
@@ -1226,6 +1786,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(true).build();
for (int i = 0; i < 500; ++i) {
@@ -1249,6 +1810,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(true).build();
for (int i = 0; i < 500; ++i) {
@@ -1270,6 +1832,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(true).build();
for (int i = 0; i < 500; ++i) {
@@ -1292,6 +1855,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = true;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(true).build();
for (int i = 0; i < 500; ++i) {
@@ -1315,6 +1879,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(false).build();
final JobWorkItem item = new JobWorkItem.Builder().build();
@@ -1337,6 +1902,7 @@
mService.mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION = false;
mService.mConstants.API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false;
mService.updateQuotaTracker();
+ mService.resetScheduleQuota();
final JobInfo job = createJobInfo().setPersisted(true).build();
final JobWorkItem item = new JobWorkItem.Builder().build();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 2180a78..2b56ea8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -73,6 +73,7 @@
import android.util.DataUnit;
import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerInternal;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -124,6 +125,10 @@
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
+ // Used in JobStatus.
+ LocalServices.removeServiceForTest(JobSchedulerInternal.class);
+ LocalServices.addService(JobSchedulerInternal.class, mock(JobSchedulerInternal.class));
+
// Freeze the clocks at this moment in time
JobSchedulerService.sSystemClock =
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 05780eb..1de7e37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -21,6 +21,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.EXEMPTED_INDEX;
import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
@@ -45,6 +46,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
@@ -582,6 +585,40 @@
}
@Test
+ public void testGetEffectiveStandbyBucket_buggyApp() {
+ when(mJobSchedulerInternal.isAppConsideredBuggy(
+ anyInt(), anyString(), anyInt(), anyString()))
+ .thenReturn(true);
+
+ final JobInfo jobInfo = new JobInfo.Builder(1234, TEST_JOB_COMPONENT).build();
+ JobStatus job = createJobStatus(jobInfo);
+
+ // Exempt apps be exempting.
+ job.setStandbyBucket(EXEMPTED_INDEX);
+ assertEquals(EXEMPTED_INDEX, job.getEffectiveStandbyBucket());
+
+ // Actual bucket is higher than the buggy cap, so the cap comes into effect.
+ job.setStandbyBucket(ACTIVE_INDEX);
+ assertEquals(WORKING_INDEX, job.getEffectiveStandbyBucket());
+
+ // Buckets at the cap or below shouldn't be affected.
+ job.setStandbyBucket(WORKING_INDEX);
+ assertEquals(WORKING_INDEX, job.getEffectiveStandbyBucket());
+
+ job.setStandbyBucket(FREQUENT_INDEX);
+ assertEquals(FREQUENT_INDEX, job.getEffectiveStandbyBucket());
+
+ job.setStandbyBucket(RARE_INDEX);
+ assertEquals(RARE_INDEX, job.getEffectiveStandbyBucket());
+
+ job.setStandbyBucket(RESTRICTED_INDEX);
+ assertEquals(RESTRICTED_INDEX, job.getEffectiveStandbyBucket());
+
+ job.setStandbyBucket(NEVER_INDEX);
+ assertEquals(NEVER_INDEX, job.getEffectiveStandbyBucket());
+ }
+
+ @Test
public void testModifyingInternalFlags() {
final JobInfo jobInfo =
new JobInfo.Builder(101, new ComponentName("foo", "bar"))
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index fb59ea2..7cc01e1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -58,6 +58,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerInternal;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.controllers.PrefetchController.PcConstants;
@@ -135,6 +136,9 @@
when(mJobSchedulerService.getPackagesForUidLocked(anyInt()))
.thenAnswer(invocationOnMock
-> mPackagesForUid.get(invocationOnMock.getArgument(0)));
+ // Used in JobStatus.
+ doReturn(mock(JobSchedulerInternal.class))
+ .when(() -> LocalServices.getService(JobSchedulerInternal.class));
// Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
// in the past, and PrefetchController sometimes floors values at 0, so if the test time
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 6f713e0..dce162c 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
@@ -85,6 +85,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
+import com.android.server.job.JobSchedulerInternal;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobStore;
import com.android.server.job.controllers.QuotaController.ExecutionStats;
@@ -190,6 +191,8 @@
doReturn(mPowerAllowlistInternal)
.when(() -> LocalServices.getService(PowerAllowlistInternal.class));
// Used in JobStatus.
+ doReturn(mock(JobSchedulerInternal.class))
+ .when(() -> LocalServices.getService(JobSchedulerInternal.class));
doReturn(mPackageManagerInternal)
.when(() -> LocalServices.getService(PackageManagerInternal.class));
// Used in QuotaController.Handler.
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
index 43f77bf..e8e1dac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -109,8 +109,8 @@
public void recordScreenPolicy_disabledByFlag_noop() {
DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/);
+ mScreenUndimDetector.readValuesFromDeviceConfig();
- setup();
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, POLICY_DIM);
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, POLICY_BRIGHT);
@@ -120,7 +120,7 @@
@Test
public void recordScreenPolicy_samePolicy_noop() {
for (int policy : ALL_POLICIES) {
- setup();
+ resetDetector();
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, policy);
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, policy);
@@ -154,7 +154,7 @@
if (from == POLICY_DIM && to == POLICY_BRIGHT) {
continue;
}
- setup();
+ resetDetector();
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, from);
mScreenUndimDetector.recordScreenPolicy(DEFAULT_DISPLAY_GROUP, to);
@@ -295,7 +295,8 @@
@Test
public void recordScreenPolicy_dimToNonBright_resets() {
for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE)) {
- setup();
+ resetDetector();
+
mScreenUndimDetector.mUndimCounter = 1;
mScreenUndimDetector.mUndimCounterStartedMillis = 123;
mScreenUndimDetector.mWakeLock.acquire();
@@ -313,7 +314,8 @@
@Test
public void recordScreenPolicy_brightToNonDim_resets() {
for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE)) {
- setup();
+ resetDetector();
+
mScreenUndimDetector.mUndimCounter = 1;
mScreenUndimDetector.mUndimCounterStartedMillis = 123;
mScreenUndimDetector.mWakeLock.acquire();
@@ -356,4 +358,9 @@
}
}
}
+
+ private void resetDetector() {
+ mScreenUndimDetector.reset();
+ mScreenUndimDetector.mCurrentScreenPolicy = 0;
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 51e521d..bc5e720 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -17,8 +17,10 @@
package com.android.server.wallpaper;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
+import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.os.FileObserver.CLOSE_WRITE;
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -90,7 +92,6 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -106,6 +107,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.List;
/**
* Tests for the {@link WallpaperManagerService} class.
@@ -262,6 +264,25 @@
}
/**
+ * Tests that the fundamental fields are set by the main WallpaperData constructor
+ */
+ @Test
+ public void testWallpaperDataConstructor() {
+ final int testUserId = MIN_SECONDARY_USER_ID;
+ for (int which: List.of(FLAG_LOCK, FLAG_SYSTEM)) {
+ WallpaperData newWallpaperData = new WallpaperData(testUserId, which);
+ assertEquals(which, newWallpaperData.mWhich);
+ assertEquals(testUserId, newWallpaperData.userId);
+
+ WallpaperData wallpaperData = mService.getWallpaperSafeLocked(testUserId, which);
+ assertEquals(wallpaperData.cropFile.getAbsolutePath(),
+ newWallpaperData.cropFile.getAbsolutePath());
+ assertEquals(wallpaperData.wallpaperFile.getAbsolutePath(),
+ newWallpaperData.wallpaperFile.getAbsolutePath());
+ }
+ }
+
+ /**
* Tests that internal basic data should be correct after boot up.
*/
@Test
@@ -278,10 +299,8 @@
/**
* Tests setWallpaperComponent and clearWallpaper should work as expected.
- * TODO ignored since the assumption never passes. to be investigated.
*/
@Test
- @Ignore("b/264533465")
public void testSetThenClearComponent() {
// Skip if there is no pre-defined default wallpaper component.
assumeThat(sDefaultWallpaperComponent,
@@ -405,10 +424,7 @@
fail("exception occurred while writing system wallpaper attributes");
}
- WallpaperData shouldMatchSystem = new WallpaperData(systemWallpaperData.userId,
- systemWallpaperData.wallpaperFile.getParentFile(),
- systemWallpaperData.wallpaperFile.getAbsolutePath(),
- systemWallpaperData.cropFile.getAbsolutePath());
+ WallpaperData shouldMatchSystem = new WallpaperData(0, FLAG_SYSTEM);
try {
TypedXmlPullParser parser = Xml.newBinaryPullParser();
mService.mWallpaperDataParser.parseWallpaperAttributes(parser, shouldMatchSystem, true);
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 662477d..8346050 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -26,6 +26,7 @@
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_STARTED_UI_SHOWING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -48,6 +49,7 @@
import android.app.trust.ITrustManager;
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.ComponentInfoInternal;
@@ -104,6 +106,7 @@
@Mock private KeyStore mKeyStore;
@Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver;
@Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger;
+ @Mock BiometricSensorPrivacy mBiometricSensorPrivacy;
private Random mRandom;
private IBinder mToken;
@@ -210,6 +213,40 @@
}
@Test
+ public void testOnErrorReceived_lockoutError() throws RemoteException {
+ setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
+ setupFace(1 /* id */, 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) {
+ assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+ session.onCookieReceived(
+ session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
+ }
+ assertTrue(session.allCookiesReceived());
+ assertEquals(STATE_AUTH_STARTED, session.getState());
+
+ // Either of strong sensor's lockout should cancel both sensors.
+ final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
+ session.onErrorReceived(0, cookie1, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, 0);
+ for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+ assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
+ }
+ assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState());
+
+ // If the sensor is STATE_CANCELING, delayed onAuthenticationRejected() shouldn't change the
+ // session state to STATE_AUTH_PAUSED.
+ session.onAuthenticationRejected(1);
+ assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState());
+ }
+
+ @Test
public void testCancelReducesAppetiteForCookies() throws Exception {
setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
mock(IBiometricAuthenticator.class));
@@ -571,7 +608,8 @@
promptInfo,
TEST_PACKAGE,
checkDevicePolicyManager,
- mContext);
+ mContext,
+ mBiometricSensorPrivacy);
}
private AuthSession createAuthSession(List<BiometricSensor> sensors,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
new file mode 100644
index 0000000..0c98c8d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.server.biometrics;
+
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+
+import static com.android.server.biometrics.sensors.LockoutTracker.LOCKOUT_NONE;
+
+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.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.ITrustManager;
+import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.PromptInfo;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+@Presubmit
+@SmallTest
+public class PreAuthInfoTest {
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ private static final int SENSOR_ID_FACE = 1;
+ private static final String TEST_PACKAGE_NAME = "PreAuthInfoTestPackage";
+
+ @Mock
+ IBiometricAuthenticator mFaceAuthenticator;
+ @Mock
+ Context mContext;
+ @Mock
+ ITrustManager mTrustManager;
+ @Mock
+ DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ BiometricService.SettingObserver mSettingObserver;
+ @Mock
+ BiometricSensorPrivacy mBiometricSensorPrivacyUtil;
+
+ @Before
+ public void setup() throws RemoteException {
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt())).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
+ .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+ when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
+ when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
+ when(mFaceAuthenticator.getLockoutModeForUser(anyInt()))
+ .thenReturn(LOCKOUT_NONE);
+ }
+
+ @Test
+ public void testFaceAuthentication_whenCameraPrivacyIsEnabled() throws Exception {
+ when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(true);
+
+ BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
+ BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
+ @Override
+ boolean confirmationAlwaysRequired(int userId) {
+ return false;
+ }
+
+ @Override
+ boolean confirmationSupported() {
+ return false;
+ }
+ };
+ PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setConfirmationRequested(false /* requireConfirmation */);
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */);
+ PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor),
+ 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil);
+
+ assertThat(preAuthInfo.eligibleSensors).isEmpty();
+ }
+
+ @Test
+ public void testFaceAuthentication_whenCameraPrivacyIsDisabled() throws Exception {
+ when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(false);
+
+ BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
+ BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
+ @Override
+ boolean confirmationAlwaysRequired(int userId) {
+ return false;
+ }
+
+ @Override
+ boolean confirmationSupported() {
+ return false;
+ }
+ };
+ PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setConfirmationRequested(false /* requireConfirmation */);
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */);
+ PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor),
+ 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil);
+
+ assertThat(preAuthInfo.eligibleSensors).hasSize(1);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index 046b01c..359d711 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -152,28 +152,6 @@
}
@Test
- public void testLockoutEndsOperation() throws RemoteException {
- final FaceAuthenticationClient client = createClient(2);
- client.start(mCallback);
- client.onLockoutPermanent();
-
- verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
- eq(FACE_ERROR_LOCKOUT_PERMANENT), anyInt());
- verify(mCallback).onClientFinished(client, false);
- }
-
- @Test
- public void testTemporaryLockoutEndsOperation() throws RemoteException {
- final FaceAuthenticationClient client = createClient(2);
- client.start(mCallback);
- client.onLockoutTimed(1000);
-
- verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
- eq(FACE_ERROR_LOCKOUT), anyInt());
- verify(mCallback).onClientFinished(client, false);
- }
-
- @Test
public void notifyHalWhenContextChanges() throws RemoteException {
final FaceAuthenticationClient client = createClient();
client.start(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
index 6a45d5f..faece4f 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
@@ -23,15 +23,19 @@
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
+import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.sensor.IVirtualSensorCallback;
+import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.hardware.Sensor;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -39,12 +43,16 @@
import com.android.server.LocalServices;
import com.android.server.sensors.SensorManagerInternal;
+import com.google.common.collect.Iterables;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@Presubmit
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -54,14 +62,17 @@
private static final String VIRTUAL_SENSOR_NAME = "VirtualAccelerometer";
private static final int SENSOR_HANDLE = 7;
+ private static final int VIRTUAL_SENSOR_TYPE = Sensor.TYPE_ACCELEROMETER;
+
@Mock
private SensorManagerInternal mSensorManagerInternalMock;
@Mock
private IVirtualSensorCallback mVirtualSensorCallback;
- private SensorController mSensorController;
+ @Mock
+ private IVirtualDevice mVirtualDevice;
+
private VirtualSensorEvent mSensorEvent;
private VirtualSensorConfig mVirtualSensorConfig;
- private IBinder mSensorToken;
@Before
public void setUp() throws Exception {
@@ -70,12 +81,10 @@
LocalServices.removeServiceForTest(SensorManagerInternal.class);
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
- mSensorController = new SensorController(VIRTUAL_DEVICE_ID, mVirtualSensorCallback);
mSensorEvent = new VirtualSensorEvent.Builder(new float[] { 1f, 2f, 3f}).build();
mVirtualSensorConfig =
- new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME)
+ new VirtualSensorConfig.Builder(VIRTUAL_SENSOR_TYPE, VIRTUAL_SENSOR_NAME)
.build();
- mSensorToken = new Binder("sensorToken");
}
@Test
@@ -86,62 +95,84 @@
Throwable thrown = assertThrows(
RuntimeException.class,
- () -> mSensorController.createSensor(mSensorToken, mVirtualSensorConfig));
+ () -> new SensorController(mVirtualDevice, VIRTUAL_DEVICE_ID,
+ mVirtualSensorCallback, List.of(mVirtualSensorConfig)));
assertThat(thrown.getCause().getMessage())
.contains("Received an invalid virtual sensor handle");
}
@Test
- public void createSensor_success() {
- doCreateSensorSuccessfully();
+ public void createSensor_success() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
- assertThat(mSensorController.getSensorDescriptors()).isNotEmpty();
+ assertThat(sensorController.getSensorDescriptors()).isNotEmpty();
}
@Test
- public void sendSensorEvent_invalidToken_throwsException() {
- doCreateSensorSuccessfully();
+ public void getSensorByHandle_success() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
+
+ VirtualSensor sensor = sensorController.getSensorByHandle(SENSOR_HANDLE);
+
+ assertThat(sensor).isNotNull();
+ assertThat(sensor.getHandle()).isEqualTo(SENSOR_HANDLE);
+ assertThat(sensor.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
+ assertThat(sensor.getType()).isEqualTo(VIRTUAL_SENSOR_TYPE);
+ }
+
+ @Test
+ public void getSensorByHandle_invalidHandle_returnsNull() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
+ final int invalidSensorHandle = 123456;
+
+ assertThat(sensorController.getSensorByHandle(invalidSensorHandle)).isNull();
+ }
+
+ @Test
+ public void sendSensorEvent_invalidToken_throwsException() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
assertThrows(
IllegalArgumentException.class,
- () -> mSensorController.sendSensorEvent(
+ () -> sensorController.sendSensorEvent(
new Binder("invalidSensorToken"), mSensorEvent));
}
@Test
- public void sendSensorEvent_success() {
- doCreateSensorSuccessfully();
+ public void sendSensorEvent_success() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
- mSensorController.sendSensorEvent(mSensorToken, mSensorEvent);
+ clearInvocations(mSensorManagerInternalMock);
+ IBinder token = Iterables.getOnlyElement(sensorController.getSensorDescriptors().keySet());
+
+ sensorController.sendSensorEvent(token, mSensorEvent);
verify(mSensorManagerInternalMock).sendSensorEvent(
SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, mSensorEvent.getTimestampNanos(),
mSensorEvent.getValues());
}
@Test
- public void unregisterSensor_invalidToken_throwsException() {
- doCreateSensorSuccessfully();
+ public void close_unregistersSensors() throws Exception {
+ SensorController sensorController = doCreateSensorSuccessfully();
- assertThrows(
- IllegalArgumentException.class,
- () -> mSensorController.unregisterSensor(new Binder("invalidSensorToken")));
- }
-
- @Test
- public void unregisterSensor_success() {
- doCreateSensorSuccessfully();
-
- mSensorController.unregisterSensor(mSensorToken);
+ sensorController.close();
verify(mSensorManagerInternalMock).removeRuntimeSensor(SENSOR_HANDLE);
- assertThat(mSensorController.getSensorDescriptors()).isEmpty();
+ assertThat(sensorController.getSensorDescriptors()).isEmpty();
}
- private void doCreateSensorSuccessfully() {
+ private SensorController doCreateSensorSuccessfully() throws RemoteException {
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
anyInt(), anyInt(), anyString(), anyString(), anyFloat(), anyFloat(), anyFloat(),
anyInt(), anyInt(), anyInt(), any());
- assertThat(mSensorController.createSensor(mSensorToken, mVirtualSensorConfig))
- .isEqualTo(SENSOR_HANDLE);
+ doReturn(VIRTUAL_DEVICE_ID).when(mVirtualDevice).getDeviceId();
+
+ SensorController sensorController = new SensorController(mVirtualDevice, VIRTUAL_DEVICE_ID,
+ mVirtualSensorCallback, List.of(mVirtualSensorConfig));
+
+ List<VirtualSensor> sensors = sensorController.getSensorList();
+ assertThat(sensors).hasSize(1);
+ assertThat(sensors.get(0).getHandle()).isEqualTo(SENSOR_HANDLE);
+ return sensorController;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 8884dba..379c8b7 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -359,7 +359,6 @@
mInputController = new InputController(mNativeWrapperMock,
new Handler(TestableLooper.get(this).getLooper()),
mContext.getSystemService(WindowManager.class), threadVerifier);
- mSensorController = new SensorController(VIRTUAL_DEVICE_ID_1, mVirtualSensorCallback);
mCameraAccessController =
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
@@ -370,6 +369,7 @@
mLocalService = mVdms.getLocalServiceInstance();
mVdm = mVdms.new VirtualDeviceManagerImpl();
mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1);
+ mSensorController = mDeviceImpl.getSensorControllerForTest();
}
@After
@@ -1722,7 +1722,7 @@
VirtualDeviceParams params) {
VirtualDeviceImpl virtualDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, mVdms, new Binder(), ownerUid, virtualDeviceId,
- mInputController, mSensorController, mCameraAccessController
+ mInputController, mCameraAccessController
/* onDeviceCloseListener= */ /*deviceId -> mVdms.removeVirtualDevice(deviceId)*/,
mPendingTrampolineCallback, mActivityListener, mSoundEffectListener,
mRunningAppsChangedCallback, params, new DisplayManagerGlobal(mIDisplayManager));
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 5f19887..e457119 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -143,25 +143,13 @@
}
@Test
- public void constructor_contentProtection_serviceInfoThrows_noBlocklistManager() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentProtectionServiceInfoConstructorShouldThrow = true;
-
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
- assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
- verifyZeroInteractions(mMockContentProtectionBlocklistManager);
- }
-
- @Test
public void constructor_contentProtection_enabled_createsBlocklistManager() {
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt());
}
@@ -361,6 +349,21 @@
.getContentCaptureManagerServiceStub()
.onLoginDetected(PARCELED_EVENTS);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ assertThat(mRemoteContentProtectionServicesCreated).isEqualTo(0);
+ verifyZeroInteractions(mMockRemoteContentProtectionService);
+ }
+
+ @Test
+ public void onLoginDetected_invalidPermissions() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentProtectionServiceInfoConstructorShouldThrow = true;
+ mContentCaptureManagerService = new TestContentCaptureManagerService();
+
+ mContentCaptureManagerService
+ .getContentCaptureManagerServiceStub()
+ .onLoginDetected(PARCELED_EVENTS);
+
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
assertThat(mRemoteContentProtectionServicesCreated).isEqualTo(0);
verifyZeroInteractions(mMockRemoteContentProtectionService);
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
index 2f57fd3..9135ef3 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
@@ -16,8 +16,6 @@
package com.android.server.contentprotection;
-import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
@@ -29,8 +27,8 @@
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.UserHandle;
+import android.service.contentcapture.IContentProtectionService;
import android.view.contentcapture.ContentCaptureEvent;
-import android.view.contentcapture.IContentCaptureDirectManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -63,7 +61,7 @@
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
- @Mock private IContentCaptureDirectManager mMockContentCaptureDirectManager;
+ @Mock private IContentProtectionService mMockContentProtectionService;
private RemoteContentProtectionService mRemoteContentProtectionService;
@@ -79,7 +77,7 @@
@Test
public void doesNotAutoConnect() {
assertThat(mConnectCallCount).isEqualTo(0);
- verifyZeroInteractions(mMockContentCaptureDirectManager);
+ verifyZeroInteractions(mMockContentProtectionService);
}
@Test
@@ -98,8 +96,7 @@
mRemoteContentProtectionService.onLoginDetected(events);
- verify(mMockContentCaptureDirectManager)
- .sendEvents(events, FLUSH_REASON_LOGIN_DETECTED, /* options= */ null);
+ verify(mMockContentProtectionService).onLoginDetected(events);
}
private final class TestRemoteContentProtectionService extends RemoteContentProtectionService {
@@ -109,15 +106,15 @@
}
@Override // from ServiceConnector
- public synchronized AndroidFuture<IContentCaptureDirectManager> connect() {
+ public synchronized AndroidFuture<IContentProtectionService> connect() {
mConnectCallCount++;
- return AndroidFuture.completedFuture(mMockContentCaptureDirectManager);
+ return AndroidFuture.completedFuture(mMockContentProtectionService);
}
@Override // from ServiceConnector
- public boolean run(@NonNull ServiceConnector.VoidJob<IContentCaptureDirectManager> job) {
+ public boolean run(@NonNull ServiceConnector.VoidJob<IContentProtectionService> job) {
try {
- job.run(mMockContentCaptureDirectManager);
+ job.run(mMockContentProtectionService);
} catch (Exception ex) {
fail("Unexpected exception: " + ex);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 5837b21..708421d 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -52,6 +52,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -376,6 +377,116 @@
assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA);
}
+ @Test
+ public void testValidLuxThrottling() throws Exception {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
+ mDisplayDeviceConfig.getLuxThrottlingData();
+ assertEquals(2, luxThrottlingData.size());
+
+ Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
+ assertEquals(2, adaptiveOnBrightnessPoints.size());
+ assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
+ assertEquals(0.5f, adaptiveOnBrightnessPoints.get(5000f), SMALL_DELTA);
+
+ Map<Float, Float> adaptiveOffBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.DEFAULT);
+ assertEquals(2, adaptiveOffBrightnessPoints.size());
+ assertEquals(0.35f, adaptiveOffBrightnessPoints.get(1500f), SMALL_DELTA);
+ assertEquals(0.55f, adaptiveOffBrightnessPoints.get(5500f), SMALL_DELTA);
+ }
+
+ @Test
+ public void testInvalidLuxThrottling() throws Exception {
+ setupDisplayDeviceConfigFromDisplayConfigFile(getContent(getInvalidLuxThrottling()));
+
+ Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
+ mDisplayDeviceConfig.getLuxThrottlingData();
+ assertEquals(1, luxThrottlingData.size());
+
+ Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
+ assertEquals(1, adaptiveOnBrightnessPoints.size());
+ assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
+ }
+
+ private String getValidLuxThrottling() {
+ return "<luxThrottling>\n"
+ + " <brightnessLimitMap>\n"
+ + " <type>adaptive</type>\n"
+ + " <map>\n"
+ + " <point>"
+ + " <first>1000</first>\n"
+ + " <second>0.3</second>\n"
+ + " </point>"
+ + " <point>"
+ + " <first>5000</first>\n"
+ + " <second>0.5</second>\n"
+ + " </point>"
+ + " </map>\n"
+ + " </brightnessLimitMap>\n"
+ + " <brightnessLimitMap>\n"
+ + " <type>default</type>\n"
+ + " <map>\n"
+ + " <point>"
+ + " <first>1500</first>\n"
+ + " <second>0.35</second>\n"
+ + " </point>"
+ + " <point>"
+ + " <first>5500</first>\n"
+ + " <second>0.55</second>\n"
+ + " </point>"
+ + " </map>\n"
+ + " </brightnessLimitMap>\n"
+ + "</luxThrottling>";
+ }
+
+ private String getInvalidLuxThrottling() {
+ return "<luxThrottling>\n"
+ + " <brightnessLimitMap>\n"
+ + " <type>adaptive</type>\n"
+ + " <map>\n"
+ + " <point>"
+ + " <first>1000</first>\n"
+ + " <second>0.3</second>\n"
+ + " </point>"
+ + " <point>" // second > hbm.transitionPoint, skipped
+ + " <first>1500</first>\n"
+ + " <second>0.9</second>\n"
+ + " </point>"
+ + " <point>" // same lux value, skipped
+ + " <first>1000</first>\n"
+ + " <second>0.5</second>\n"
+ + " </point>"
+ + " </map>\n"
+ + " </brightnessLimitMap>\n"
+ + " <brightnessLimitMap>\n" // Same type, skipped
+ + " <type>adaptive</type>\n"
+ + " <map>\n"
+ + " <point>"
+ + " <first>2000</first>\n"
+ + " <second>0.35</second>\n"
+ + " </point>"
+ + " <point>"
+ + " <first>6000</first>\n"
+ + " <second>0.55</second>\n"
+ + " </point>"
+ + " </map>\n"
+ + " </brightnessLimitMap>\n"
+ + " <brightnessLimitMap>\n" // Invalid points only, skipped
+ + " <type>default</type>\n"
+ + " <map>\n"
+ + " <point>"
+ + " <first>2500</first>\n"
+ + " <second>0.99</second>\n"
+ + " </point>"
+ + " </map>\n"
+ + " </brightnessLimitMap>\n"
+ + "</luxThrottling>";
+ }
+
private String getRefreshThermalThrottlingMaps() {
return "<refreshRateThrottlingMap>\n"
+ " <refreshRateThrottlingPoint>\n"
@@ -405,6 +516,10 @@
}
private String getContent() {
+ return getContent(getValidLuxThrottling());
+ }
+
+ private String getContent(String brightnessCapConfig) {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<displayConfiguration>\n"
+ "<name>Example Display</name>"
@@ -462,6 +577,7 @@
+ "</point>\n"
+ "</sdrHdrRatioMap>\n"
+ "</highBrightnessMode>\n"
+ + brightnessCapConfig
+ "<screenOffBrightnessSensor>\n"
+ "<type>sensor_12345</type>\n"
+ "<name>Sensor 12345</name>\n"
@@ -731,8 +847,12 @@
}
private void setupDisplayDeviceConfigFromDisplayConfigFile() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile(getContent());
+ }
+
+ private void setupDisplayDeviceConfigFromDisplayConfigFile(String content) throws IOException {
Path tempFile = Files.createTempFile("display_config", ".tmp");
- Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
+ Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8));
mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
mDisplayDeviceConfig.initFromFile(tempFile.toFile());
}
diff --git a/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java
new file mode 100644
index 0000000..c379d6b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.server.display;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.PowerManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.display.DisplayDeviceConfig.BrightnessLimitMapType;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class NormalBrightnessModeControllerTest {
+ private static final float FLOAT_TOLERANCE = 0.001f;
+
+ private final NormalBrightnessModeController mController = new NormalBrightnessModeController();
+
+ @Keep
+ private static Object[][] brightnessData() {
+ return new Object[][]{
+ // no brightness config
+ {0, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, new HashMap<>(),
+ PowerManager.BRIGHTNESS_MAX},
+ {0, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, new HashMap<>(),
+ PowerManager.BRIGHTNESS_MAX},
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, new HashMap<>(),
+ PowerManager.BRIGHTNESS_MAX},
+ // Auto brightness - on, config only for default
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of(
+ BrightnessLimitMapType.DEFAULT,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f)
+ ), 0.2f},
+ // Auto brightness - off, config only for default
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of(
+ BrightnessLimitMapType.DEFAULT,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f)
+ ), 0.2f},
+ // Auto brightness - off, config only for adaptive
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of(
+ BrightnessLimitMapType.ADAPTIVE,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f)
+ ), PowerManager.BRIGHTNESS_MAX},
+ // Auto brightness - on, config only for adaptive
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of(
+ BrightnessLimitMapType.ADAPTIVE,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f)
+ ), 0.2f},
+ // Auto brightness - on, config for both
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of(
+ BrightnessLimitMapType.DEFAULT,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f),
+ BrightnessLimitMapType.ADAPTIVE,
+ ImmutableMap.of(99f, 0.3f, 101f, 0.4f)
+ ), 0.4f},
+ // Auto brightness - off, config for both
+ {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of(
+ BrightnessLimitMapType.DEFAULT,
+ ImmutableMap.of(99f, 0.1f, 101f, 0.2f),
+ BrightnessLimitMapType.ADAPTIVE,
+ ImmutableMap.of(99f, 0.3f, 101f, 0.4f)
+ ), 0.2f},
+ // Auto brightness - on, config for both, ambient high
+ {1000, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of(
+ BrightnessLimitMapType.DEFAULT,
+ ImmutableMap.of(1000f, 0.1f, 2000f, 0.2f),
+ BrightnessLimitMapType.ADAPTIVE,
+ ImmutableMap.of(99f, 0.3f, 101f, 0.4f)
+ ), PowerManager.BRIGHTNESS_MAX},
+ };
+ }
+
+ @Test
+ @Parameters(method = "brightnessData")
+ public void testReturnsCorrectMaxBrightness(float ambientLux, int autoBrightnessState,
+ Map<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessConfig,
+ float expectedBrightness) {
+ setupController(ambientLux, autoBrightnessState, maxBrightnessConfig);
+
+ assertEquals(expectedBrightness, mController.getCurrentBrightnessMax(), FLOAT_TOLERANCE);
+ }
+
+ private void setupController(float ambientLux, int autoBrightnessState,
+ Map<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessConfig) {
+ mController.onAmbientLuxChange(ambientLux);
+ mController.setAutoBrightnessState(autoBrightnessState);
+ mController.resetNbmData(maxBrightnessConfig);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 851d8f9..f05fa65 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -101,12 +101,6 @@
mMonitor.onEndDream();
super.onEndDream();
}
-
- @Override
- public void onWakeUp(@NonNull Runnable onCompleteCallback) {
- mMonitor.onWakeUp();
- super.onWakeUp(onCompleteCallback);
- }
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index bdf3a5f..0aa72d0 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -18,9 +18,6 @@
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
-import static com.android.server.hdmi.Constants.ADDR_RECORDER_1;
-import static com.android.server.hdmi.Constants.ADDR_RECORDER_2;
-import static com.android.server.hdmi.Constants.ADDR_RECORDER_3;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_DESTINATION;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER;
import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER_LONG;
@@ -43,9 +40,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
/** Tests for {@link com.android.server.hdmi.HdmiCecMessageValidator} class. */
@SmallTest
@@ -651,13 +646,9 @@
@Test
public void isValid_activeSource() {
- // Only source devices should broadcast <Active Source> messages.
- List<Integer> nonSourceDevicesAddresses = Arrays.asList(ADDR_RECORDER_1, ADDR_RECORDER_2,
- ADDR_AUDIO_SYSTEM, ADDR_RECORDER_3);
-
for (int i = 0; i < ADDR_BROADCAST; ++i) {
String message = Integer.toHexString(i) + "F:82:10:00";
- if (nonSourceDevicesAddresses.contains(i)) {
+ if (i == ADDR_AUDIO_SYSTEM) {
assertMessageValidity(message).isEqualTo(ERROR_SOURCE);
} else {
assertMessageValidity(message).isEqualTo(OK);
diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
index 416b1f4..c36122b 100644
--- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
@@ -40,8 +40,7 @@
import com.android.server.input.BatteryController.BluetoothBatteryManager
import com.android.server.input.BatteryController.BluetoothBatteryManager.BluetoothBatteryListener
import com.android.server.input.BatteryController.POLLING_PERIOD_MILLIS
-import com.android.server.input.BatteryController.UEventManager
-import com.android.server.input.BatteryController.UEventManager.UEventBatteryListener
+import com.android.server.input.BatteryController.UEventBatteryListener
import com.android.server.input.BatteryController.USI_BATTERY_VALIDITY_DURATION_MILLIS
import org.hamcrest.Description
import org.hamcrest.Matcher
diff --git a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
index 677144c..2f1a376 100644
--- a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
@@ -23,9 +23,12 @@
import android.os.IInputConstants
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
+import android.provider.Settings
+import android.test.mock.MockContentResolver
import android.view.Display
import android.view.PointerIcon
import androidx.test.InstrumentationRegistry
+import com.android.internal.util.test.FakeSettingsProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -33,6 +36,8 @@
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
@@ -44,7 +49,9 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.junit.MockitoJUnit
+import org.mockito.stubbing.OngoingStubbing
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -58,7 +65,10 @@
class InputManagerServiceTests {
@get:Rule
- val rule = MockitoJUnit.rule()!!
+ val mockitoRule = MockitoJUnit.rule()!!
+
+ @get:Rule
+ val fakeSettingsProviderRule = FakeSettingsProvider.rule()!!
@Mock
private lateinit var native: NativeInputManagerService
@@ -66,17 +76,25 @@
@Mock
private lateinit var wmCallbacks: InputManagerService.WindowManagerCallbacks
+ @Mock
+ private lateinit var uEventManager: UEventManager
+
private lateinit var service: InputManagerService
private lateinit var localService: InputManagerInternal
private lateinit var context: Context
private lateinit var testLooper: TestLooper
+ private lateinit var contentResolver: MockContentResolver
@Before
fun setup() {
context = spy(ContextWrapper(InstrumentationRegistry.getContext()))
+ contentResolver = MockContentResolver(context)
+ contentResolver.addProvider(Settings.AUTHORITY, FakeSettingsProvider())
+ whenever(context.contentResolver).thenReturn(contentResolver)
testLooper = TestLooper()
service =
- InputManagerService(object : InputManagerService.Injector(context, testLooper.looper) {
+ InputManagerService(object : InputManagerService.Injector(
+ context, testLooper.looper, uEventManager) {
override fun getNativeService(
service: InputManagerService?
): NativeInputManagerService {
@@ -92,9 +110,37 @@
}
@Test
+ fun testStart() {
+ verifyZeroInteractions(native)
+
+ service.start()
+ verify(native).start()
+ }
+
+ @Test
+ fun testInputSettingsUpdatedOnSystemRunning() {
+ verifyZeroInteractions(native)
+
+ service.systemRunning()
+
+ verify(native).setPointerSpeed(anyInt())
+ verify(native).setTouchpadPointerSpeed(anyInt())
+ verify(native).setTouchpadNaturalScrollingEnabled(anyBoolean())
+ verify(native).setTouchpadTapToClickEnabled(anyBoolean())
+ verify(native).setTouchpadRightClickZoneEnabled(anyBoolean())
+ verify(native).setShowTouches(anyBoolean())
+ verify(native).reloadPointerIcons()
+ verify(native).setMotionClassifierEnabled(anyBoolean())
+ verify(native).setMaximumObscuringOpacityForTouch(anyFloat())
+ verify(native).setStylusPointerIconEnabled(anyBoolean())
+ // TODO(b/286078544): There is no need to call this more than once.
+ verify(native, times(3)).setKeyRepeatConfiguration(anyInt(), anyInt())
+ }
+
+ @Test
fun testPointerDisplayUpdatesWhenDisplayViewportsChanged() {
val displayId = 123
- `when`(wmCallbacks.pointerDisplayId).thenReturn(displayId)
+ whenever(wmCallbacks.pointerDisplayId).thenReturn(displayId)
val viewports = listOf<DisplayViewport>()
localService.setDisplayViewports(viewports)
verify(native).setDisplayViewports(any(Array<DisplayViewport>::class.java))
@@ -337,3 +383,5 @@
thread.join(100 /*millis*/)
}
}
+
+private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 67158f2..3f4a4fb 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -105,6 +105,8 @@
private lateinit var iInputManager: IInputManager
@Mock
private lateinit var native: NativeInputManagerService
+ @Mock
+ private lateinit var uEventManager: UEventManager
private lateinit var keyboardBacklightController: KeyboardBacklightController
private lateinit var context: Context
private lateinit var dataStore: PersistentDataStore
@@ -130,7 +132,7 @@
})
testLooper = TestLooper()
keyboardBacklightController = KeyboardBacklightController(context, native, dataStore,
- testLooper.looper, FakeAnimatorFactory())
+ testLooper.looper, FakeAnimatorFactory(), uEventManager)
InputManagerGlobal.resetInstance(iInputManager)
val inputManager = InputManager(context)
`when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
new file mode 100644
index 0000000..c9724a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright 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.server.input
+
+import android.hardware.input.KeyboardLayout
+import android.icu.util.ULocale
+import android.platform.test.annotations.Presubmit
+import android.view.InputDevice
+import android.view.inputmethod.InputMethodSubtype
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThrows
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+private fun createKeyboard(
+ deviceId: Int,
+ vendorId: Int,
+ productId: Int,
+ languageTag: String?,
+ layoutType: String?
+): InputDevice =
+ InputDevice.Builder()
+ .setId(deviceId)
+ .setName("Device $deviceId")
+ .setDescriptor("descriptor $deviceId")
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
+ .setExternal(true)
+ .setVendorId(vendorId)
+ .setProductId(productId)
+ .setKeyboardLanguageTag(languageTag)
+ .setKeyboardLayoutType(layoutType)
+ .build()
+
+private fun createImeSubtype(
+ imeSubtypeId: Int,
+ languageTag: String,
+ layoutType: String
+): InputMethodSubtype =
+ InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(imeSubtypeId)
+ .setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType).build()
+
+/**
+ * Tests for {@link KeyboardMetricsCollector}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:KeyboardMetricsCollectorTests
+ */
+@Presubmit
+class KeyboardMetricsCollectorTests {
+
+ companion object {
+ const val DEVICE_ID = 1
+ const val DEFAULT_VENDOR_ID = 123
+ const val DEFAULT_PRODUCT_ID = 456
+ }
+
+ @Test
+ fun testCreateKeyboardConfigurationEvent_throwsExceptionWithoutAnyLayoutConfiguration() {
+ assertThrows(IllegalStateException::class.java) {
+ KeyboardMetricsCollector.KeyboardConfigurationEvent.Builder(
+ createKeyboard(
+ DEVICE_ID,
+ DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID,
+ null,
+ null
+ )
+ ).build()
+ }
+ }
+
+ @Test
+ fun testCreateKeyboardConfigurationEvent_throwsExceptionWithInvalidLayoutSelectionCriteria() {
+ assertThrows(IllegalStateException::class.java) {
+ KeyboardMetricsCollector.KeyboardConfigurationEvent.Builder(
+ createKeyboard(
+ DEVICE_ID,
+ DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID,
+ null,
+ null
+ )
+ ).addLayoutSelection(createImeSubtype(1, "en-US", "qwerty"), null, 123).build()
+ }
+ }
+
+ @Test
+ fun testCreateKeyboardConfigurationEvent_withMultipleConfigurations() {
+ val builder = KeyboardMetricsCollector.KeyboardConfigurationEvent.Builder(
+ createKeyboard(
+ DEVICE_ID,
+ DEFAULT_VENDOR_ID,
+ DEFAULT_PRODUCT_ID,
+ "de-CH",
+ "qwertz"
+ )
+ )
+ val event = builder.addLayoutSelection(
+ createImeSubtype(1, "en-US", "qwerty"),
+ KeyboardLayout(null, "English(US)(Qwerty)", null, 0, null, 0, 0, 0),
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+ ).addLayoutSelection(
+ createImeSubtype(2, "en-US", "azerty"),
+ null,
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER
+ ).addLayoutSelection(
+ createImeSubtype(3, "en-US", "qwerty"),
+ KeyboardLayout(null, "German", null, 0, null, 0, 0, 0),
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
+ ).setIsFirstTimeConfiguration(true).build()
+
+ assertEquals(
+ "KeyboardConfigurationEvent should pick vendor ID from provided InputDevice",
+ DEFAULT_VENDOR_ID,
+ event.vendorId
+ )
+ assertEquals(
+ "KeyboardConfigurationEvent should pick product ID from provided InputDevice",
+ DEFAULT_PRODUCT_ID,
+ event.productId
+ )
+ assertTrue(event.isFirstConfiguration)
+
+ assertEquals(
+ "KeyboardConfigurationEvent should contain 3 configurations provided",
+ 3,
+ event.layoutConfigurations.size
+ )
+ assertExpectedLayoutConfiguration(
+ event.layoutConfigurations[0],
+ "en-US",
+ KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwerty"),
+ "English(US)(Qwerty)",
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+ )
+ assertExpectedLayoutConfiguration(
+ event.layoutConfigurations[1],
+ "en-US",
+ KeyboardLayout.LayoutType.getLayoutTypeEnumValue("azerty"),
+ KeyboardMetricsCollector.DEFAULT_LAYOUT,
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER
+ )
+ assertExpectedLayoutConfiguration(
+ event.layoutConfigurations[2],
+ "de-CH",
+ KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwertz"),
+ "German",
+ KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
+ )
+ }
+
+ private fun assertExpectedLayoutConfiguration(
+ configuration: KeyboardMetricsCollector.LayoutConfiguration,
+ expectedLanguageTag: String,
+ expectedLayoutType: Int,
+ expectedSelectedLayout: String,
+ expectedLayoutSelectionCriteria: Int
+ ) {
+ assertEquals(expectedLanguageTag, configuration.keyboardLanguageTag)
+ assertEquals(expectedLayoutType, configuration.keyboardLayoutType)
+ assertEquals(expectedSelectedLayout, configuration.keyboardLayoutName)
+ assertEquals(expectedLayoutSelectionCriteria, configuration.layoutSelectionCriteria)
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e960e99..fe2ac17 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -254,6 +254,8 @@
.thenReturn(true);
when(res.getBoolean(eq(com.android.internal.R.bool.config_strongAuthRequiredOnBoot)))
.thenReturn(true);
+ when(res.getBoolean(eq(com.android.internal.R.bool.config_repairModeSupported)))
+ .thenReturn(true);
return res;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 36dc6c5..a029db9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -84,6 +84,11 @@
}
@Override
+ File getRepairModePersistentDataFile() {
+ return remapToStorageDir(super.getRepairModePersistentDataFile());
+ }
+
+ @Override
PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
return mPersistentDataBlockManager;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 10ed882..23f14f8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -457,6 +457,31 @@
assertEquals(2, PersistentData.TYPE_SP_WEAVER);
}
+ @Test
+ public void testRepairMode_emptyPersistentData() {
+ assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
+ }
+
+ @Test
+ public void testRepairMode_writeGatekeeperPersistentData() {
+ mStorage.writeRepairModePersistentData(
+ PersistentData.TYPE_SP_GATEKEEPER, SOME_USER_ID, PAYLOAD);
+
+ final PersistentData data = mStorage.readRepairModePersistentData();
+ assertEquals(PersistentData.TYPE_SP_GATEKEEPER, data.type);
+ assertArrayEquals(PAYLOAD, data.payload);
+ }
+
+ @Test
+ public void testRepairMode_writeWeaverPersistentData() {
+ mStorage.writeRepairModePersistentData(
+ PersistentData.TYPE_SP_WEAVER, SOME_USER_ID, PAYLOAD);
+
+ final PersistentData data = mStorage.readRepairModePersistentData();
+ assertEquals(PersistentData.TYPE_SP_WEAVER, data.type);
+ assertArrayEquals(PAYLOAD, data.payload);
+ }
+
private static void assertArrayEquals(byte[] expected, byte[] actual) {
if (!Arrays.equals(expected, actual)) {
fail("expected:<" + Arrays.toString(expected) +
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
new file mode 100644
index 0000000..70150c5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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.server.locksettings;
+
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
+import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.app.PropertyInvalidatedCache;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.VerifyCredentialResponse;
+import com.android.server.locksettings.LockSettingsStorage.PersistentData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests {
+
+ @Before
+ public void setUp() throws Exception {
+ PropertyInvalidatedCache.disableForTestMode();
+ mService.initializeSyntheticPassword(PRIMARY_USER_ID);
+ }
+
+ @Test
+ public void verifyPin_writeRepairModePW() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ }
+
+ @Test
+ public void verifyPattern_writeRepairModePW() {
+ mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPattern("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ }
+
+ @Test
+ public void verifyPassword_writeRepairModePW() {
+ mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPassword("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ }
+
+ @Test
+ public void verifyCredential_writeRepairModePW_repairModeActive() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+
+ setRepairModeActive(true);
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ }
+
+ @Test
+ public void deleteRepairModePersistentData() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+
+ mService.deleteRepairModePersistentDataIfNeeded();
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ }
+
+ @Test
+ public void verifyPin_userRepairMode() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyPattern_userRepairMode() {
+ mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPattern("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPattern("4321"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyPassword_userRepairMode() {
+ mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPassword("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPassword("4321"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyCredential_userRepairMode_repairModeIsNotActive() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyCredential_userRepairMode_wrongPin() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(newPin("5678"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ private void setRepairModeActive(boolean active) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ArchiveManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ArchiveManagerTest.java
new file mode 100644
index 0000000..73a6bb7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ArchiveManagerTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.server.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.IntentSender;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.pm.pkg.PackageStateInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ArchiveManagerTest {
+
+ private static final String PACKAGE = "com.example";
+ private static final String CALLER_PACKAGE = "com.vending";
+ private static final int USER_ID = 1;
+
+ @Mock private IntentSender mIntentSender;
+ @Mock private PackageManagerService mPm;
+ @Mock private Computer mComputer;
+ @Mock private PackageStateInternal mPackageState;
+ private InstallSource mInstallSource =
+ InstallSource.create(
+ CALLER_PACKAGE,
+ CALLER_PACKAGE,
+ CALLER_PACKAGE,
+ Binder.getCallingUid(),
+ CALLER_PACKAGE,
+ /* installerAttributionTag= */ null,
+ /* packageSource= */ 0);
+
+ private ArchiveManager mArchiveManager;
+ private int mCallingUid;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mArchiveManager = new ArchiveManager(mPm);
+ mCallingUid = Binder.getCallingUid();
+ when(mPm.snapshotComputer()).thenReturn(mComputer);
+ when(mComputer.getNameForUid(eq(mCallingUid))).thenReturn(CALLER_PACKAGE);
+ when(mComputer.getPackageStateInternal(eq(PACKAGE))).thenReturn(mPackageState);
+ when(mPackageState.getInstallSource()).thenReturn(mInstallSource);
+ }
+
+ @Test
+ public void archiveApp_callerPackageNameIncorrect() {
+ Exception e = assertThrows(
+ SecurityException.class,
+ () -> mArchiveManager.archiveApp(PACKAGE, "different", USER_ID, mIntentSender)
+ );
+ assertThat(e).hasMessageThat().isEqualTo(
+ String.format(
+ "The callerPackageName %s set by the caller doesn't match the "
+ + "caller's own package name %s.",
+ "different",
+ CALLER_PACKAGE));
+ }
+
+ @Test
+ public void archiveApp_packageNotInstalled() {
+ when(mComputer.getPackageStateInternal(eq(PACKAGE))).thenReturn(null);
+
+ Exception e = assertThrows(
+ PackageManager.NameNotFoundException.class,
+ () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, USER_ID, mIntentSender)
+ );
+ assertThat(e).hasMessageThat().isEqualTo(String.format("Package %s not found.", PACKAGE));
+ }
+
+ @Test
+ public void archiveApp_callerNotInstallerOfRecord() {
+ InstallSource otherInstallSource =
+ InstallSource.create(
+ CALLER_PACKAGE,
+ CALLER_PACKAGE,
+ /* installerPackageName= */ "different",
+ Binder.getCallingUid(),
+ CALLER_PACKAGE,
+ /* installerAttributionTag= */ null,
+ /* packageSource= */ 0);
+ when(mPackageState.getInstallSource()).thenReturn(otherInstallSource);
+
+ Exception e = assertThrows(
+ SecurityException.class,
+ () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, USER_ID, mIntentSender)
+ );
+ assertThat(e).hasMessageThat().isEqualTo(
+ String.format("Caller is not the installer of record for %s.", PACKAGE));
+ }
+
+ @Test
+ public void archiveApp_callerNotUpdateOwner() {
+ InstallSource otherInstallSource =
+ InstallSource.create(
+ CALLER_PACKAGE,
+ CALLER_PACKAGE,
+ CALLER_PACKAGE,
+ Binder.getCallingUid(),
+ /* updateOwnerPackageName= */ "different",
+ /* installerAttributionTag= */ null,
+ /* packageSource= */ 0);
+ when(mPackageState.getInstallSource()).thenReturn(otherInstallSource);
+
+ Exception e = assertThrows(
+ SecurityException.class,
+ () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, USER_ID, mIntentSender)
+ );
+ assertThat(e).hasMessageThat().isEqualTo(
+ String.format("Caller is not the update owner for %s.", PACKAGE));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 7c1845f..0f5fb91 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -125,6 +125,8 @@
import java.io.OutputStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -4014,8 +4016,10 @@
ShortcutUser user = new ShortcutUser(mService, 0);
- File corruptedShortcutPackage = new File("/data/local/tmp/cts/content/",
+ File corruptedShortcutPackage = new File(getTestContext().getFilesDir(),
"broken_shortcut.xml");
+ Files.copy(new File("/data/local/tmp/cts/content/", "broken_shortcut.xml").toPath(),
+ corruptedShortcutPackage.toPath(), StandardCopyOption.REPLACE_EXISTING);
assertNull(ShortcutPackage.loadFromFile(mService, user, corruptedShortcutPackage, false));
}
@@ -4116,6 +4120,11 @@
try (Writer os = new FileWriter(mService.getUserFile(USER_10).getBaseFile())) {
os.write("<?xml version='1.0' encoding='utf");
}
+ ShortcutPackage sp = mService.getUserShortcutsLocked(USER_0).getPackageShortcutsIfExists(
+ CALLING_PACKAGE_1);
+ try (Writer os = new FileWriter(sp.getShortcutPackageItemFile().getPath())) {
+ os.write("<?xml version='1.0' encoding='utf");
+ }
// Restore.
initService();
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 70cd0dc..c80ff45 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -1066,9 +1066,13 @@
@SuppressWarnings("GuardedBy")
@Test
public void testScreensaverActivateOnSleepEnabled_powered_afterTimeout_goesToDreaming() {
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_dreamsSupported))
+ .thenReturn(true);
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
doAnswer(inv -> {
when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index aa6ee09..0b13f9a 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -52,7 +52,7 @@
private static final int SOUND_TRIGGER_MODE = 0; // SOUND_TRIGGER_MODE_ALL_ENABLED
private static final int DEFAULT_SOUND_TRIGGER_MODE =
PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY;
- private static final String BATTERY_SAVER_CONSTANTS = "disable_vibration=true,"
+ private static final String BATTERY_SAVER_CONSTANTS = "disable_vibration=false,"
+ "advertise_is_enabled=true,"
+ "disable_animation=false,"
+ "enable_firewall=true,"
@@ -117,7 +117,7 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
- testServiceDefaultValue_On(ServiceType.VIBRATION);
+ testServiceDefaultValue_Off(ServiceType.VIBRATION);
}
@SmallTest
@@ -211,7 +211,7 @@
private void verifyBatterySaverConstantsUpdated() {
final PowerSaveState vibrationState =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.VIBRATION);
- assertThat(vibrationState.batterySaverEnabled).isTrue();
+ assertThat(vibrationState.batterySaverEnabled).isFalse();
final PowerSaveState animationState =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.ANIMATION);
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index f44c1d1..4315254 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
@@ -36,6 +37,7 @@
<uses-permission android:name="android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG" />
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
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 8f7f2f6..eaf4838 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -61,6 +61,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
+import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
@@ -80,6 +81,7 @@
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
@@ -120,12 +122,14 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import android.Manifest;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -182,11 +186,14 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.WorkSource;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
@@ -352,6 +359,9 @@
private PermissionManager mPermissionManager;
@Mock
private DevicePolicyManagerInternal mDevicePolicyManager;
+ @Mock
+ private PowerManager mPowerManager;
+ private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
new TestPostNotificationTrackerFactory();
@@ -432,8 +442,9 @@
private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>();
@Override
- public PostNotificationTracker newTracker() {
- PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker();
+ public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) {
+ PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker(
+ optionalWakeLock);
mCreatedTrackers.add(tracker);
return tracker;
}
@@ -564,6 +575,22 @@
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
+ // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks.
+ // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks,
+ // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't
+ // call release twice, etc) and we want the test to fail if such misuse happens, too.
+ PowerManager realPowerManager = mContext.getSystemService(PowerManager.class);
+ when(mPowerManager.newWakeLock(anyInt(), anyString())).then(
+ (Answer<WakeLock>) invocation -> {
+ WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0),
+ invocation.getArgument(1));
+ mAcquiredWakeLocks.add(wl);
+ return wl;
+ });
+ mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, true);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "true", false);
+
// apps allowed as convos
mService.setStringArrayResourceValue(PKG_O);
@@ -580,7 +607,7 @@
mock(TelephonyManager.class),
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
- mPostNotificationTrackerFactory);
+ mPowerManager, mPostNotificationTrackerFactory);
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
@@ -688,6 +715,13 @@
}
@After
+ public void assertAllWakeLocksReleased() {
+ for (WakeLock wakeLock : mAcquiredWakeLocks) {
+ assertThat(wakeLock.isHeld()).isFalse();
+ }
+ }
+
+ @After
public void tearDown() throws Exception {
if (mFile != null) mFile.delete();
clearDeviceConfig();
@@ -1488,7 +1522,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -1509,7 +1543,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -1805,6 +1839,128 @@
}
@Test
+ public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception {
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_acquiresAndReleasesWakeLock", 0,
+ generateNotificationRecord(null).getNotification(), 0);
+
+ verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
+
+ waitForIdle();
+
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
+ }
+
+ @Test
+ public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception {
+ // Simulate not enqueued due to rejected inputs.
+ assertThrows(Exception.class,
+ () -> mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0,
+ /* notification= */ null, 0));
+
+ verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
+ }
+
+ @Test
+ public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception {
+ // Simulate not enqueued due to snoozing inputs.
+ when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any()))
+ .thenReturn("zzzzzzz");
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0,
+ generateNotificationRecord(null).getNotification(), 0);
+
+ verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
+
+ waitForIdle();
+
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
+ }
+
+ @Test
+ public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception {
+ // Simulate enqueued but not posted due to missing small icon.
+ Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .build();
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0,
+ notif, 0);
+
+ verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue();
+
+ waitForIdle();
+
+ // NLSes were not called.
+ verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean());
+
+ assertThat(mAcquiredWakeLocks).hasSize(1);
+ assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse();
+ }
+
+ @Test
+ public void enqueueNotification_setsWakeLockWorkSource() throws Exception {
+ // Use a "full" mock for the PowerManager (instead of the one that delegates to the real
+ // service) so we can return a mocked WakeLock that we can verify() on.
+ reset(mPowerManager);
+ WakeLock wakeLock = mock(WakeLock.class);
+ when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_setsWakeLockWorkSource", 0,
+ generateNotificationRecord(null).getNotification(), 0);
+ waitForIdle();
+
+ InOrder inOrder = inOrder(mPowerManager, wakeLock);
+ inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString());
+ inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, PKG)));
+ inOrder.verify(wakeLock).acquire(anyLong());
+ inOrder.verify(wakeLock).release();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void enqueueNotification_wakeLockSystemPropertyOff_noWakeLock() throws Exception {
+ mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "true", false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_setsWakeLockWorkSource", 0,
+ generateNotificationRecord(null).getNotification(), 0);
+ waitForIdle();
+
+ verifyZeroInteractions(mPowerManager);
+ }
+
+ @Test
+ public void enqueueNotification_wakeLockDeviceConfigOff_noWakeLock() throws Exception {
+ mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, true);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "false", false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "enqueueNotification_setsWakeLockWorkSource", 0,
+ generateNotificationRecord(null).getNotification(), 0);
+ waitForIdle();
+
+ verifyZeroInteractions(mPowerManager);
+ }
+
+ @Test
public void testCancelNonexistentNotification() throws Exception {
mBinderService.cancelNotificationWithTag(PKG, PKG,
"testCancelNonexistentNotification", 0, 0);
@@ -4363,7 +4519,7 @@
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -4382,7 +4538,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(update.getKey(),
update.getSbn().getPackageName(), update.getUid(),
- mPostNotificationTrackerFactory.newTracker());
+ mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -4402,7 +4558,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(update.getKey(),
update.getSbn().getPackageName(), update.getUid(),
- mPostNotificationTrackerFactory.newTracker());
+ mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -4422,7 +4578,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(update.getKey(),
update.getSbn().getPackageName(),
- update.getUid(), mPostNotificationTrackerFactory.newTracker());
+ update.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -4436,13 +4592,13 @@
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
r = generateNotificationRecord(mTestNotificationChannel, 1, null, false);
r.setCriticality(CriticalNotificationExtractor.CRITICAL);
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
mService.addEnqueuedNotification(r);
runnable.run();
@@ -5092,7 +5248,7 @@
mService.new PostNotificationRunnable(original.getKey(),
original.getSbn().getPackageName(),
original.getUid(),
- mPostNotificationTrackerFactory.newTracker());
+ mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -5116,7 +5272,7 @@
mService.new PostNotificationRunnable(update.getKey(),
update.getSbn().getPackageName(),
update.getUid(),
- mPostNotificationTrackerFactory.newTracker());
+ mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -7538,7 +7694,7 @@
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -10236,7 +10392,7 @@
mService.addEnqueuedNotification(r);
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -10253,7 +10409,7 @@
mService.addEnqueuedNotification(r);
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -10270,7 +10426,7 @@
mService.addEnqueuedNotification(r);
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), mPostNotificationTrackerFactory.newTracker());
+ r.getUid(), mPostNotificationTrackerFactory.newTracker(null));
runnable.run();
waitForIdle();
@@ -10363,7 +10519,7 @@
// normal blocked notifications - blocked
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats).registerBlocked(any());
@@ -10381,7 +10537,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats).registerBlocked(any());
@@ -10394,7 +10550,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats, never()).registerBlocked(any());
@@ -10408,7 +10564,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats, never()).registerBlocked(any());
@@ -10422,7 +10578,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats).registerBlocked(any());
@@ -10437,7 +10593,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats).registerBlocked(any());
@@ -10450,7 +10606,7 @@
mService.addEnqueuedNotification(r);
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(),
- mPostNotificationTrackerFactory.newTracker()).run();
+ mPostNotificationTrackerFactory.newTracker(null)).run();
waitForIdle();
verify(mUsageStats).registerBlocked(any());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
index beab107..0b147c3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
@@ -18,6 +18,8 @@
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
+import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -33,6 +35,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
+import com.android.internal.util.FrameworkStatsLog;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -155,4 +158,54 @@
// Then: should return false
assertFalse(NotificationRecordLogger.isNonDismissible(p.r));
}
+
+ @Test
+ public void testGetFsiState_stickyHunFlagDisabled_zero() {
+ final int fsiState = NotificationRecordLogger.getFsiState(
+ /* isStickyHunFlagEnabled= */ false,
+ /* hasFullScreenIntent= */ true,
+ /* hasFsiRequestedButDeniedFlag= */ true,
+ /* eventType= */ NOTIFICATION_POSTED);
+ assertEquals(0, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_isUpdate_zero() {
+ final int fsiState = NotificationRecordLogger.getFsiState(
+ /* isStickyHunFlagEnabled= */ true,
+ /* hasFullScreenIntent= */ true,
+ /* hasFsiRequestedButDeniedFlag= */ true,
+ /* eventType= */ NOTIFICATION_UPDATED);
+ assertEquals(0, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_hasFsi_allowedEnum() {
+ final int fsiState = NotificationRecordLogger.getFsiState(
+ /* isStickyHunFlagEnabled= */ true,
+ /* hasFullScreenIntent= */ true,
+ /* hasFsiRequestedButDeniedFlag= */ false,
+ /* eventType= */ NOTIFICATION_POSTED);
+ assertEquals(FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__FSI_ALLOWED, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_fsiPermissionDenied_deniedEnum() {
+ final int fsiState = NotificationRecordLogger.getFsiState(
+ /* isStickyHunFlagEnabled= */ true,
+ /* hasFullScreenIntent= */ false,
+ /* hasFsiRequestedButDeniedFlag= */ true,
+ /* eventType= */ NOTIFICATION_POSTED);
+ assertEquals(FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__FSI_DENIED, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_noFsi_noFsiEnum() {
+ final int fsiState = NotificationRecordLogger.getFsiState(
+ /* isStickyHunFlagEnabled= */ true,
+ /* hasFullScreenIntent= */ false,
+ /* hasFsiRequestedButDeniedFlag= */ false,
+ /* eventType= */ NOTIFICATION_POSTED);
+ assertEquals(FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__NO_FSI, fsiState);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index 6668f85..a88ab18 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -115,11 +115,19 @@
PREFERRED_CONSTRUCTORS = ImmutableMap.of(
Notification.Builder.class,
Notification.Builder.class.getConstructor(Context.class, String.class));
+
+ EXCLUDED_SETTERS_OVERLOADS = ImmutableMultimap.<Class<?>, Method>builder()
+ .put(RemoteViews.class,
+ // b/245950570: Tries to connect to service and will crash.
+ RemoteViews.class.getMethod("setRemoteAdapter",
+ int.class, Intent.class))
+ .build();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
+ // Setters that shouldn't be called, for various reasons (but NOT because they are KNOWN_BAD).
private static final Multimap<Class<?>, String> EXCLUDED_SETTERS =
ImmutableMultimap.<Class<?>, String>builder()
// Handled by testAllStyles().
@@ -134,6 +142,9 @@
.put(RemoteViews.class, "mergeRemoteViews")
.build();
+ // Same as above, but specific overloads that should not be called.
+ private static final Multimap<Class<?>, Method> EXCLUDED_SETTERS_OVERLOADS;
+
private Context mContext;
@Rule
@@ -146,10 +157,12 @@
@Test // This is a meta-test, checks that the generators are not broken.
public void verifyTest() {
- Generated<Notification> notification = buildNotification(mContext, /* styleClass= */ null,
- /* extenderClass= */ null, /* actionExtenderClass= */ null,
+ Generated<Notification> notification = buildNotification(mContext,
+ /* styleClass= */ Notification.MessagingStyle.class,
+ /* extenderClass= */ Notification.WearableExtender.class,
+ /* actionExtenderClass= */ Notification.Action.WearableExtender.class,
/* includeRemoteViews= */ true);
- assertThat(notification.includedUris.size()).isAtLeast(20);
+ assertThat(notification.includedUris.size()).isAtLeast(730);
}
@Test
@@ -479,6 +492,7 @@
|| method.getReturnType().equals(clazz))
&& method.getParameterCount() >= 1
&& !EXCLUDED_SETTERS.containsEntry(clazz, method.getName())
+ && !EXCLUDED_SETTERS_OVERLOADS.containsEntry(clazz, method)
&& Arrays.stream(method.getParameterTypes())
.noneMatch(excludingParameterTypes::contains)) {
methods.put(method.getName(), method);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 48ad86d..47340c1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -36,6 +36,9 @@
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER;
@@ -48,7 +51,6 @@
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
-
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertNull;
@@ -102,6 +104,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@@ -185,6 +188,7 @@
@Mock Context mContext;
@Mock ZenModeHelper mMockZenModeHelper;
@Mock AppOpsManager mAppOpsManager;
+ @Mock PermissionManager mPermissionManager;
private NotificationManager.Policy mTestNotificationPolicy;
@@ -218,6 +222,8 @@
InstrumentationRegistry.getContext().getResources());
when(mContext.getContentResolver()).thenReturn(
InstrumentationRegistry.getContext().getContentResolver());
+ when(mPm.getPermissionFlags(any(), any(), any()))
+ .thenReturn(PackageManager.FLAG_PERMISSION_USER_SET);
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getApplicationInfo()).thenReturn(legacy);
// most tests assume badging is enabled
@@ -303,7 +309,8 @@
mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager,
+ mStatsEventBuilderFactory, false);
resetZenModeHelper();
mAudioAttributes = new AudioAttributes.Builder()
@@ -645,7 +652,7 @@
@Test
public void testReadXml_oldXml_migrates() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
String xml = "<ranking version=\"2\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
@@ -711,7 +718,7 @@
@Test
public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
@@ -789,7 +796,7 @@
@Test
public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
String xml = "<ranking version=\"3\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -846,7 +853,7 @@
@Test
public void testReadXml_newXml_permissionNotificationOff() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
String xml = "<ranking version=\"3\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -903,7 +910,7 @@
@Test
public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, true);
String xml = "<ranking version=\"4\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -959,7 +966,7 @@
@Test
public void testReadXml_oldXml_migration_NoUid() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
String xml = "<ranking version=\"2\">\n"
@@ -992,7 +999,7 @@
@Test
public void testReadXml_newXml_noMigration_NoUid() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID);
String xml = "<ranking version=\"3\">\n"
@@ -1024,7 +1031,7 @@
@Test
public void testChannelXmlForNonBackup_postMigration() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
@@ -1110,7 +1117,7 @@
@Test
public void testChannelXmlForBackup_postMigration() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
@@ -1202,7 +1209,7 @@
@Test
public void testChannelXmlForBackup_postMigration_noExternal() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false));
@@ -1287,7 +1294,7 @@
@Test
public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false));
@@ -1498,7 +1505,7 @@
new FileNotFoundException("")).thenReturn(resId);
mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+ mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -2443,7 +2450,7 @@
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
@@ -2474,7 +2481,7 @@
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
// create notification channel that can bypass dnd, but app is blocked
@@ -2498,7 +2505,7 @@
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
// create notification channel that can bypass dnd, but app is blocked
@@ -2552,7 +2559,7 @@
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean());
@@ -2565,7 +2572,7 @@
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean());
@@ -3668,7 +3675,7 @@
+ "</package>\n"
+ "</ranking>\n";
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadByteArrayXml(preQXml.getBytes(), true, USER_SYSTEM);
@@ -3682,7 +3689,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3752,7 +3759,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3765,7 +3772,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3779,7 +3786,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3795,7 +3802,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3851,7 +3858,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -3889,7 +3896,7 @@
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
loadStreamXml(baos, false, UserHandle.USER_ALL);
@@ -4547,7 +4554,7 @@
@Test
public void testPlaceholderConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
final String xml = "<ranking version=\"1\">\n"
@@ -4567,7 +4574,7 @@
@Test
public void testNormalConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
final String xml = "<ranking version=\"1\">\n"
@@ -4587,7 +4594,7 @@
@Test
public void testNoConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
final String xml = "<ranking version=\"1\">\n"
@@ -4607,7 +4614,7 @@
@Test
public void testDeleted_noTime() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
final String xml = "<ranking version=\"1\">\n"
@@ -4627,7 +4634,7 @@
@Test
public void testDeleted_twice() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.createNotificationChannel(
@@ -4642,7 +4649,7 @@
@Test
public void testDeleted_recentTime() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.createNotificationChannel(
@@ -4661,7 +4668,7 @@
null);
parser.nextTag();
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.readXml(parser, true, USER_SYSTEM);
@@ -4673,7 +4680,7 @@
@Test
public void testUnDelete_time() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
mHelper.createNotificationChannel(
@@ -4695,7 +4702,7 @@
@Test
public void testDeleted_longTime() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
- mPermissionHelper, mLogger,
+ mPermissionHelper, mPermissionManager, mLogger,
mAppOpsManager, mStatsEventBuilderFactory, false);
long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30);
@@ -5464,4 +5471,93 @@
verifyZeroInteractions(mHandler);
}
+
+ @Test
+ public void testGetFsiState_flagDisabled_zero() {
+ final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
+ /* requestedFsiPermission */ true, /* isFlagEnabled= */ false);
+
+ assertEquals(0, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_appDidNotRequest_enumNotRequested() {
+ final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
+ /* requestedFsiPermission */ false, /* isFlagEnabled= */ true);
+
+ assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_permissionGranted_enumGranted() {
+ when(mPermissionManager.checkPermissionForPreflight(any(), any()))
+ .thenReturn(PermissionManager.PERMISSION_GRANTED);
+
+ final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
+ /* requestedFsiPermission= */ true, /* isFlagEnabled= */ true);
+
+ assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_permissionSoftDenied_enumDenied() {
+ when(mPermissionManager.checkPermissionForPreflight(any(), any()))
+ .thenReturn(PermissionManager.PERMISSION_SOFT_DENIED);
+
+ final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
+ /* requestedFsiPermission = */ true, /* isFlagEnabled= */ true);
+
+ assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState);
+ }
+
+ @Test
+ public void testGetFsiState_permissionHardDenied_enumDenied() {
+ when(mPermissionManager.checkPermissionForPreflight(any(), any()))
+ .thenReturn(PermissionManager.PERMISSION_HARD_DENIED);
+
+ final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0,
+ /* requestedFsiPermission = */ true, /* isFlagEnabled= */ true);
+
+ assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState);
+ }
+
+ @Test
+ public void testIsFsiPermissionUserSet_appDidNotRequest_false() {
+ final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
+ /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED,
+ /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET,
+ /* isStickyHunFlagEnabled= */ true);
+
+ assertFalse(isUserSet);
+ }
+
+ @Test
+ public void testIsFsiPermissionUserSet_flagDisabled_false() {
+ final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
+ /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED,
+ /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET,
+ /* isStickyHunFlagEnabled= */ false);
+
+ assertFalse(isUserSet);
+ }
+
+ @Test
+ public void testIsFsiPermissionUserSet_userSet_true() {
+ final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
+ /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED,
+ /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET,
+ /* isStickyHunFlagEnabled= */ true);
+
+ assertTrue(isUserSet);
+ }
+
+ @Test
+ public void testIsFsiPermissionUserSet_notUserSet_false() {
+ final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0,
+ /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED,
+ /* currentPermissionFlags= */ ~PackageManager.FLAG_PERMISSION_USER_SET,
+ /* isStickyHunFlagEnabled= */ true);
+
+ assertFalse(isUserSet);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
index 4840f07..131aaa0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -138,22 +138,22 @@
@Test
public void testEstimateCatchesUpQuickly() {
- long nextEventTime = postEvents(mTestStartTime, 10, 20); // 20 events at 100Hz
+ long nextEventTime = postEvents(mTestStartTime, 100, 30); // 30 events at 10Hz
final float firstBurstRate = mEstimator.getRate(nextEventTime);
- assertThat(firstBurstRate).isWithin(10f).of(100);
+ assertThat(firstBurstRate).isWithin(2f).of(10);
nextEventTime += HOURS.toMillis(3); // 3 hours later...
- nextEventTime = postEvents(nextEventTime, 10, 20); // same burst of 20 events at 100Hz
+ nextEventTime = postEvents(nextEventTime, 100, 30); // same burst of 30 events at 10Hz
- // Catching up. Rate is not yet 100, since we had a long period of inactivity...
+ // Catching up. Rate is not yet 10, since we had a long period of inactivity...
float secondBurstRate = mEstimator.getRate(nextEventTime);
- assertThat(secondBurstRate).isWithin(10f).of(60);
+ assertThat(secondBurstRate).isWithin(1f).of(6);
// ... but after a few more events, we are there.
- nextEventTime = postEvents(nextEventTime, 10, 10); // 10 more events at 100Hz
+ nextEventTime = postEvents(nextEventTime, 100, 10); // 10 more events at 10Hz
secondBurstRate = mEstimator.getRate(nextEventTime);
- assertThat(secondBurstRate).isWithin(10f).of(100);
+ assertThat(secondBurstRate).isWithin(1f).of(10);
}
/** @return the next event time. */
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 66c1e35..81c573d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -48,6 +48,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionManager;
@@ -169,6 +170,7 @@
mock(UsageStatsManagerInternal.class), mock(TelecomManager.class),
mock(NotificationChannelLogger.class), new TestableFlagResolver(),
mock(PermissionManager.class),
+ mock(PowerManager.class),
new NotificationManagerService.PostNotificationTrackerFactory() {});
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 6509591..a0e6cf5 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -82,7 +82,10 @@
],
platform_apis: true,
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
certificate: "platform",
diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
index 5863e9d..6a9f283 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
@@ -58,9 +58,20 @@
mPhoneWindowManager.overrideCanStartDreaming(true);
sendKey(KEYCODE_POWER);
mPhoneWindowManager.assertDreamRequest();
+ mPhoneWindowManager.overrideIsDreaming(true);
mPhoneWindowManager.assertLockedAfterAppTransitionFinished();
}
+ @Test
+ public void testAppTransitionFinishedCalledAfterDreamStoppedWillNotLockAgain() {
+ mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_DREAM_OR_SLEEP);
+ mPhoneWindowManager.overrideCanStartDreaming(true);
+ sendKey(KEYCODE_POWER);
+ mPhoneWindowManager.assertDreamRequest();
+ mPhoneWindowManager.overrideIsDreaming(false);
+ mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished();
+ }
+
/**
* Power double-press to launch camera does not lock device when the single press behavior is to
* dream.
@@ -72,7 +83,7 @@
sendKey(KEYCODE_POWER);
sendKey(KEYCODE_POWER);
mPhoneWindowManager.assertCameraLaunch();
- mPhoneWindowManager.assertWillNotLockAfterAppTransitionFinished();
+ mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished();
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index af48cbd..766a88f 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -65,6 +65,7 @@
import android.media.AudioManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
@@ -344,6 +345,10 @@
doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean());
}
+ void overrideIsDreaming(boolean isDreaming) {
+ doReturn(isDreaming).when(mDreamManagerInternal).isDreaming();
+ }
+
void overrideDisplayState(int state) {
doReturn(state).when(mDisplay).getState();
doReturn(state == STATE_ON).when(mDisplayPolicy).isAwake();
@@ -520,19 +525,26 @@
verify(mInputManagerInternal).toggleCapsLock(anyInt());
}
- void assertWillNotLockAfterAppTransitionFinished() {
- Assert.assertFalse(mPhoneWindowManager.mLockAfterAppTransitionFinished);
- }
-
void assertLockedAfterAppTransitionFinished() {
ArgumentCaptor<AppTransitionListener> transitionCaptor =
ArgumentCaptor.forClass(AppTransitionListener.class);
verify(mWindowManagerInternal).registerAppTransitionListener(
transitionCaptor.capture());
- transitionCaptor.getValue().onAppTransitionFinishedLocked(any());
+ final IBinder token = mock(IBinder.class);
+ transitionCaptor.getValue().onAppTransitionFinishedLocked(token);
verify(mPhoneWindowManager).lockNow(null);
}
+ void assertDidNotLockAfterAppTransitionFinished() {
+ ArgumentCaptor<AppTransitionListener> transitionCaptor =
+ ArgumentCaptor.forClass(AppTransitionListener.class);
+ verify(mWindowManagerInternal).registerAppTransitionListener(
+ transitionCaptor.capture());
+ final IBinder token = mock(IBinder.class);
+ transitionCaptor.getValue().onAppTransitionFinishedLocked(token);
+ verify(mPhoneWindowManager, never()).lockNow(null);
+ }
+
void assertGoToHomescreen() {
waitForIdle();
verify(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 41fcd69..3db53eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2784,8 +2784,12 @@
testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU,
TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
- // Above T
- testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU + 1, 0);
+ testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1,
+ TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
+ // Above V
+ testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 2, 0);
} finally {
try {
DeviceConfig.setProperties(properties);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 0044e2e..4290f4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -1059,4 +1060,18 @@
assertEquals(0, mAtm.getActivityInterceptorCallbacks().size());
mAtm.mInternal.unregisterActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID);
}
+
+ @Test
+ public void testFocusTopTask() {
+ final ActivityRecord homeActivity = new ActivityBuilder(mAtm)
+ .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask())
+ .build();
+ final Task pinnedTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_PINNED)
+ .build();
+ mAtm.focusTopTask(mDisplayContent.mDisplayId);
+
+ assertTrue(homeActivity.getTask().isFocused());
+ assertFalse(pinnedTask.isFocused());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index 3a456fb..dc4e47d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
@@ -80,13 +81,27 @@
}
@Test
- public void testReturnsSkipIfTaskNotUsingActivityTypeStandard() {
+ public void testReturnsSkipIfTaskNotUsingActivityTypeStandardOrUndefined() {
final Task task = new TaskBuilder(mSupervisor).setActivityType(
ACTIVITY_TYPE_ASSISTANT).build();
assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(task).calculate());
}
@Test
+ public void testReturnsDoneIfTaskUsingActivityTypeStandard() {
+ final Task task = new TaskBuilder(mSupervisor).setActivityType(
+ ACTIVITY_TYPE_STANDARD).build();
+ assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate());
+ }
+
+ @Test
+ public void testReturnsDoneIfTaskUsingActivityTypeUndefined() {
+ final Task task = new TaskBuilder(mSupervisor).setActivityType(
+ ACTIVITY_TYPE_UNDEFINED).build();
+ assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate());
+ }
+
+ @Test
public void testReturnsSkipIfCurrentParamsHasBounds() {
final Task task = new TaskBuilder(mSupervisor).setActivityType(
ACTIVITY_TYPE_STANDARD).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 3ca35ef..8e015d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -40,7 +40,9 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -51,6 +53,8 @@
import android.app.servertransaction.ResumeActivityItem;
import android.content.ComponentName;
import android.content.pm.ActivityInfo.ScreenOrientation;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Configuration.Orientation;
import android.hardware.camera2.CameraManager;
@@ -84,7 +88,7 @@
private static final String TEST_PACKAGE_2 = "com.test.package.two";
private static final String CAMERA_ID_1 = "camera-1";
private static final String CAMERA_ID_2 = "camera-2";
-
+ private static final String TEST_PACKAGE_1_LABEL = "testPackage1";
private CameraManager mMockCameraManager;
private Handler mMockHandler;
private LetterboxConfiguration mLetterboxConfiguration;
@@ -133,17 +137,27 @@
}
@Test
- public void testOpenedCameraInSplitScreen_showToast() {
+ public void testOpenedCameraInSplitScreen_showToast() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
spyOn(mTask);
spyOn(mDisplayRotationCompatPolicy);
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mTask).getWindowingMode();
+ final PackageManager mockPackageManager = mock(PackageManager.class);
+ final ApplicationInfo mockApplicationInfo = mock(ApplicationInfo.class);
+ when(mContext.getPackageManager()).thenReturn(mockPackageManager);
+ when(mockPackageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenReturn(mockApplicationInfo);
+
+ doReturn(TEST_PACKAGE_1_LABEL).when(mockPackageManager)
+ .getApplicationLabel(mockApplicationInfo);
+
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
verify(mDisplayRotationCompatPolicy).showToast(
- R.string.display_rotation_camera_compat_toast_in_split_screen);
+ R.string.display_rotation_camera_compat_toast_in_multi_window,
+ TEST_PACKAGE_1_LABEL);
}
@Test
@@ -157,7 +171,8 @@
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
verify(mDisplayRotationCompatPolicy, never()).showToast(
- R.string.display_rotation_camera_compat_toast_in_split_screen);
+ R.string.display_rotation_camera_compat_toast_in_multi_window,
+ TEST_PACKAGE_1_LABEL);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index fb29d3a..abf21a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -641,6 +641,31 @@
// Home split secondary and home task should be invisible.
assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
splitSecondary.getVisibility(null /* starting */));
+
+ // Put another task on top of primary split.
+ final Task topSplitPrimary = new TaskBuilder(mSupervisor).setParentTask(organizer.mPrimary)
+ .setCreateActivity(true).build();
+ doReturn(false).when(topSplitPrimary).isTranslucent(any());
+ // Convert the fullscreen translucent task to opaque.
+ doReturn(false).when(translucentRootTask).isTranslucent(any());
+ translucentRootTask.moveToFront("test");
+ // The tasks of primary split are occluded by the fullscreen opaque task.
+ assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+ organizer.mPrimary.getVisibility(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+ topSplitPrimary.getVisibility(null /* starting */));
+ // Make primary split root transient-hide.
+ spyOn(splitPrimary.mTransitionController);
+ doReturn(true).when(splitPrimary.mTransitionController).isTransientHide(
+ organizer.mPrimary);
+ // The split root and its top become visible.
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+ organizer.mPrimary.getVisibility(null /* starting */));
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+ topSplitPrimary.getVisibility(null /* starting */));
+ // The bottom of primary split becomes invisible because it is occluded by topSplitPrimary.
+ assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+ splitPrimary.getVisibility(null /* starting */));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index d173ce9..3bc6450 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -337,6 +337,17 @@
// Ensure a task has moved over.
ensureTaskPlacement(task, activity);
assertTrue(task.inPinnedWindowingMode());
+
+ // The activity with fixed orientation should not apply letterbox when entering PiP.
+ final int requestedOrientation = task.getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ doReturn(requestedOrientation).when(activity).getRequestedConfigurationOrientation();
+ doReturn(false).when(activity).handlesOrientationChangeFromDescendant(anyInt());
+ final Rect bounds = new Rect(task.getBounds());
+ bounds.scale(0.5f);
+ task.setBounds(bounds);
+ assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
}
/**
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 f8fb3f0..27e6e31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -407,7 +407,6 @@
clearInvocations(translucentActivity.mLetterboxUiController);
// We destroy the first opaque activity
- mActivity.setState(DESTROYED, "testing");
mActivity.removeImmediately();
// Check that updateInheritedLetterbox() is invoked again
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index 8425844..8bd5473 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -90,19 +90,23 @@
public void packageFromDeviceConfigIgnored() {
setExceptionListAndWaitForCallback("com.test.nosplashscreen1,com.test.nosplashscreen2");
- // In list, up to T included
+ // In list, up to V included
assertIsException("com.test.nosplashscreen1", VERSION_CODES.R);
assertIsException("com.test.nosplashscreen1", VERSION_CODES.S);
assertIsException("com.test.nosplashscreen1", VERSION_CODES.TIRAMISU);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.UPSIDE_DOWN_CAKE);
+ assertIsException("com.test.nosplashscreen1", VERSION_CODES.UPSIDE_DOWN_CAKE + 1);
- // In list, after T
- assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.TIRAMISU + 1);
+ // In list, after V
+ assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.UPSIDE_DOWN_CAKE + 2);
assertIsNotException("com.test.nosplashscreen2", VERSION_CODES.CUR_DEVELOPMENT);
- // Not in list, up to T included
+ // Not in list, up to V included
assertIsNotException("com.test.splashscreen", VERSION_CODES.S);
assertIsNotException("com.test.splashscreen", VERSION_CODES.R);
assertIsNotException("com.test.splashscreen", VERSION_CODES.TIRAMISU);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.UPSIDE_DOWN_CAKE);
+ assertIsNotException("com.test.splashscreen", VERSION_CODES.UPSIDE_DOWN_CAKE + 1);
}
@Test
@@ -119,15 +123,19 @@
assertIsNotException(packageName, VERSION_CODES.R, activityInfo);
assertIsNotException(packageName, VERSION_CODES.S, activityInfo);
assertIsNotException(packageName, VERSION_CODES.TIRAMISU, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.UPSIDE_DOWN_CAKE, activityInfo);
+ assertIsNotException(packageName, VERSION_CODES.UPSIDE_DOWN_CAKE + 1, activityInfo);
- // Exception up to T
+ // Exception up to V
metaData.putBoolean("android.splashscreen.exception_opt_out", false);
assertIsException(packageName, VERSION_CODES.R, activityInfo);
assertIsException(packageName, VERSION_CODES.S, activityInfo);
assertIsException(packageName, VERSION_CODES.TIRAMISU, activityInfo);
+ assertIsException(packageName, VERSION_CODES.UPSIDE_DOWN_CAKE, activityInfo);
+ assertIsException(packageName, VERSION_CODES.UPSIDE_DOWN_CAKE + 1, activityInfo);
- // No Exception after T
- assertIsNotException(packageName, VERSION_CODES.TIRAMISU + 1, activityInfo);
+ // No Exception after V
+ assertIsNotException(packageName, VERSION_CODES.UPSIDE_DOWN_CAKE + 2, activityInfo);
assertIsNotException(packageName, VERSION_CODES.CUR_DEVELOPMENT, activityInfo);
// Edge Cases
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 b59f027..1126726 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1346,6 +1346,16 @@
activity1.setVisible(false);
abortTransition.abort();
assertTrue(activity1.isVisible());
+
+ // The mLaunchTaskBehind flag of an invisible initializing activity should not be cleared.
+ final Transition noChangeTransition = controller.createTransition(TRANSIT_OPEN);
+ noChangeTransition.collect(activity1);
+ activity1.setVisibleRequested(false);
+ activity1.setState(ActivityRecord.State.INITIALIZING, "test");
+ activity1.mLaunchTaskBehind = true;
+ mWm.mSyncEngine.abort(noChangeTransition.getSyncId());
+ noChangeTransition.finishTransition();
+ assertTrue(activity1.mLaunchTaskBehind);
}
@Test
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1888943..5b1c6b1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10318,7 +10318,7 @@
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
sDefaults.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, 300);
- sDefaults.putInt(KEY_PREFERRED_IKE_PROTOCOL_INT, 0);
+ sDefaults.putInt(KEY_PREFERRED_IKE_PROTOCOL_INT, -1);
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
index f8a1ec9..0ab3dfe 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
+++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
@@ -22,6 +22,9 @@
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="DynamicCodeLoggerIntegrationTests"/>
+ <!-- This test make uses of the event log, make sure we capture it. -->
+ <option name="logcat-options" value="-b all" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.dynamiccodeloggertest"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
diff --git a/tests/FixVibrateSetting/Android.bp b/tests/FixVibrateSetting/Android.bp
deleted file mode 100644
index bd7c701..0000000
--- a/tests/FixVibrateSetting/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-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_app {
- name: "FixVibrateSetting",
- srcs: ["**/*.java"],
- sdk_version: "current",
- certificate: "platform",
-}
diff --git a/tests/FixVibrateSetting/AndroidManifest.xml b/tests/FixVibrateSetting/AndroidManifest.xml
deleted file mode 100644
index c2d5918..0000000
--- a/tests/FixVibrateSetting/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.fixvibratesetting">
- <uses-permission android:name="android.permission.VIBRATE"/>
-
- <application>
- <activity android:name="FixVibrateSetting"
- android:label="@string/app_label"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/FixVibrateSetting/OWNERS b/tests/FixVibrateSetting/OWNERS
deleted file mode 100644
index cc63ceb..0000000
--- a/tests/FixVibrateSetting/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/vibrator/OWNERS
diff --git a/tests/FixVibrateSetting/res/drawable-hdpi/stat_sys_warning.png b/tests/FixVibrateSetting/res/drawable-hdpi/stat_sys_warning.png
deleted file mode 100644
index 37c8853..0000000
--- a/tests/FixVibrateSetting/res/drawable-hdpi/stat_sys_warning.png
+++ /dev/null
Binary files differ
diff --git a/tests/FixVibrateSetting/res/drawable-mdpi/stat_sys_warning.png b/tests/FixVibrateSetting/res/drawable-mdpi/stat_sys_warning.png
deleted file mode 100644
index be00f47..0000000
--- a/tests/FixVibrateSetting/res/drawable-mdpi/stat_sys_warning.png
+++ /dev/null
Binary files differ
diff --git a/tests/FixVibrateSetting/res/layout/fix_vibrate.xml b/tests/FixVibrateSetting/res/layout/fix_vibrate.xml
deleted file mode 100644
index c505e65..0000000
--- a/tests/FixVibrateSetting/res/layout/fix_vibrate.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- >
-
- <TextView android:id="@+id/current_setting"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginTop="30dp"
- android:layout_marginBottom="50dp"
- android:paddingLeft="8dp"
- android:paddingTop="4dp"
- android:textSize="20sp"
- android:textColor="#ffffffff"
- />
-
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal"
- >
- <Button android:id="@+id/fix"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/fix"
- />
-
- <Button android:id="@+id/unfix"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/unfix"
- />
- </LinearLayout>
-
- <Button android:id="@+id/test"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/test"
- />
-
-</LinearLayout>
-
diff --git a/tests/FixVibrateSetting/res/values/strings.xml b/tests/FixVibrateSetting/res/values/strings.xml
deleted file mode 100644
index 269cef3..0000000
--- a/tests/FixVibrateSetting/res/values/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <string name="app_label">Fix Vibrate</string>
- <string name="title">Fix vibrate setting</string>
- <string name="current_setting">"Ringer: %1$s\nNotification: %2$s"</string>
- <string name="fix">Fix the setting</string>
- <string name="unfix">Break the setting</string>
- <string name="test">Test the setting</string>
-</resources>
-
diff --git a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java b/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java
deleted file mode 100644
index 761efe4..0000000
--- a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fixvibratesetting;
-
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
-import android.os.Bundle;
-
-public class FixVibrateSetting extends Activity implements View.OnClickListener
-{
- AudioManager mAudioManager;
- NotificationManager mNotificationManager;
- TextView mCurrentSetting;
- View mFix;
- View mUnfix;
- View mTest;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.fix_vibrate);
-
- mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
- mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
-
- mCurrentSetting = (TextView)findViewById(R.id.current_setting);
-
- mFix = findViewById(R.id.fix);
- mFix.setOnClickListener(this);
-
- mUnfix = findViewById(R.id.unfix);
- mUnfix.setOnClickListener(this);
-
- mTest = findViewById(R.id.test);
- mTest.setOnClickListener(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- update();
- }
-
- private String getSettingValue(int vibrateType) {
- int setting = mAudioManager.getVibrateSetting(vibrateType);
- switch (setting) {
- case AudioManager.VIBRATE_SETTING_OFF:
- return "off";
- case AudioManager.VIBRATE_SETTING_ON:
- return "on";
- case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
- return "silent-only";
- default:
- return "unknown";
- }
- }
-
- public void onClick(View v) {
- if (v == mFix) {
- fix();
- update();
- } else if (v == mUnfix) {
- unfix();
- update();
- } else if (v == mTest) {
- test();
- update();
- }
- }
-
- private void update() {
- String ringer = getSettingValue(AudioManager.VIBRATE_TYPE_RINGER);
- String notification = getSettingValue(AudioManager.VIBRATE_TYPE_NOTIFICATION);
- String text = getString(R.string.current_setting, ringer, notification);
- mCurrentSetting.setText(text);
- }
-
- private void fix() {
- mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,
- AudioManager.VIBRATE_SETTING_ON);
- }
-
- private void unfix() {
- mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,
- AudioManager.VIBRATE_SETTING_OFF);
- }
-
- private void test() {
- Intent intent = new Intent(this, FixVibrateSetting.class);
- PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
-
- Notification n = new Notification.Builder(this)
- .setSmallIcon(R.drawable.stat_sys_warning)
- .setTicker("Test notification")
- .setWhen(System.currentTimeMillis())
- .setContentTitle("Test notification")
- .setContentText("Test notification")
- .setContentIntent(pending)
- .setVibrate(new long[] { 0, 700, 500, 1000 })
- .setAutoCancel(true)
- .build();
-
- mNotificationManager.notify(1, n);
- }
-}
-
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
index a8f1b3d..eeee7b4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
@@ -62,6 +62,33 @@
}
/**
+ * Injects a series of {@link MotionEvent}s to simulate tapping.
+ *
+ * @param point coordinates of pointer to tap
+ * @param times the number of times to tap
+ */
+ public boolean tap(@NonNull Tuple point, int times) throws InterruptedException {
+ PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER);
+ PointerCoords ptrCoord = getPointerCoord(point.x, point.y, 1, 1);
+
+ for (int i = 0; i <= times; i++) {
+ // If already tapped, inject delay in between movements
+ if (times > 0) {
+ SystemClock.sleep(50L);
+ }
+ if (!primaryPointerDown(ptrProp, ptrCoord, SystemClock.uptimeMillis())) {
+ return false;
+ }
+ // Delay before releasing tap
+ SystemClock.sleep(100L);
+ if (!primaryPointerUp(ptrProp, ptrCoord, SystemClock.uptimeMillis())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Injects a series of {@link MotionEvent}s to simulate a drag gesture without pointer release.
*
* Simulates a drag gesture without releasing the primary pointer. The primary pointer info
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index a670d68..34581bb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -17,6 +17,8 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.tools.common.datatypes.Region
+import android.tools.common.datatypes.Rect
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.helpers.FIND_TIMEOUT
@@ -36,6 +38,8 @@
ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent()
) : StandardAppHelper(instr, launcherName, component) {
+ private val gestureHelper: GestureHelper = GestureHelper(mInstrumentation)
+
fun clickRestart(wmHelper: WindowManagerStateHelper) {
val restartButton =
uiDevice.wait(
@@ -56,4 +60,64 @@
?: error("Restart dialog button not found")
wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
}
+
+ fun repositionHorizontally(displayBounds: Rect, right: Boolean) {
+ val x = if (right) displayBounds.right - BOUNDS_OFFSET else BOUNDS_OFFSET
+ reposition(x.toFloat(), displayBounds.centerY().toFloat())
+ }
+
+ fun repositionVertically(displayBounds: Rect, bottom: Boolean) {
+ val y = if (bottom) displayBounds.bottom - BOUNDS_OFFSET else BOUNDS_OFFSET
+ reposition(displayBounds.centerX().toFloat(), y.toFloat())
+ }
+
+ private fun reposition(x: Float, y: Float) {
+ val coords = GestureHelper.Tuple(x, y)
+ require(gestureHelper.tap(coords, 2)) { "Failed to reposition letterbox app" }
+ }
+
+ fun waitForAppToMoveHorizontallyTo(
+ wmHelper: WindowManagerStateHelper,
+ displayBounds: Rect,
+ right: Boolean
+ ) {
+ wmHelper.StateSyncBuilder().add("letterboxAppRepositioned") {
+ val letterboxAppWindow = getWindowRegion(wmHelper)
+ val appRegionBounds = letterboxAppWindow.bounds
+ val appWidth = appRegionBounds.width
+ return@add if (right) appRegionBounds.left == displayBounds.right - appWidth &&
+ appRegionBounds.right == displayBounds.right
+ else appRegionBounds.left == displayBounds.left &&
+ appRegionBounds.right == displayBounds.left + appWidth
+ }.waitForAndVerify()
+ }
+
+ fun waitForAppToMoveVerticallyTo(
+ wmHelper: WindowManagerStateHelper,
+ displayBounds: Rect,
+ navBarHeight: Int,
+ bottom: Boolean
+ ) {
+ wmHelper.StateSyncBuilder().add("letterboxAppRepositioned") {
+ val letterboxAppWindow = getWindowRegion(wmHelper)
+ val appRegionBounds = letterboxAppWindow.bounds
+ val appHeight = appRegionBounds.height
+ return@add if (bottom) appRegionBounds.bottom == displayBounds.bottom &&
+ appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight)
+ else appRegionBounds.top == displayBounds.top &&
+ appRegionBounds.bottom == displayBounds.top + appHeight
+ }.waitForAndVerify()
+ }
+
+ private fun getWindowRegion(wmHelper: WindowManagerStateHelper): Region {
+ val windowRegion = wmHelper.getWindowRegion(this)
+ require(!windowRegion.isEmpty) {
+ "Unable to find letterbox app window in the current state"
+ }
+ return windowRegion
+ }
+
+ companion object {
+ private const val BOUNDS_OFFSET: Int = 100
+ }
}
diff --git a/tests/SilkFX/res/layout/gainmap_transform_test.xml b/tests/SilkFX/res/layout/gainmap_transform_test.xml
new file mode 100644
index 0000000..5aeb536
--- /dev/null
+++ b/tests/SilkFX/res/layout/gainmap_transform_test.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<com.android.test.silkfx.hdr.GainmapTransformsTest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/original"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Original" />
+
+ <Button
+ android:id="@+id/scaled"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Scaled (1/3)" />
+
+ <Button
+ android:id="@+id/rotate_90"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Rotate 90" />
+
+ <Button
+ android:id="@+id/rotate_90_scaled"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Rot90+Scale" />
+
+ <Button
+ android:id="@+id/crop"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Crop" />
+
+ <Button
+ android:id="@+id/crop_200"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Crop 200" />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/source_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/sdr_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageView
+ android:id="@+id/sdr_source"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="8dp"
+ android:scaleType="fitStart" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/gainmap_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageView
+ android:id="@+id/gainmap"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="8dp"
+ android:scaleType="fitStart" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+</com.android.test.silkfx.hdr.GainmapTransformsTest>
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
index a6cdbb9..59a6078 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -55,7 +55,9 @@
Demo("Color Grid", R.layout.color_grid),
Demo("Gradient Sweep", R.layout.gradient_sweep),
Demo("Gainmap Image", R.layout.gainmap_image),
- Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false)
+ Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false),
+ Demo("Gainmap Transform Test", R.layout.gainmap_transform_test,
+ commonControls = false)
)),
DemoGroup("Materials", listOf(
Demo("Glass", GlassActivity::class),
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
index a004fb5..585320ae 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
@@ -17,7 +17,12 @@
package com.android.test.silkfx.hdr
import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.ColorMatrixColorFilter
+import android.graphics.Gainmap
import android.graphics.ImageDecoder
+import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.widget.Button
@@ -34,6 +39,25 @@
CropedSquaredScaled33
}
+fun gainmapVisualizer(gainmap: Gainmap): Bitmap {
+ val map = gainmap.gainmapContents
+ val gainmapVisualizer = Bitmap.createBitmap(map.width, map.height,
+ Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(gainmapVisualizer!!)
+ val paint = Paint()
+ paint.colorFilter = ColorMatrixColorFilter(
+ floatArrayOf(
+ 0f, 0f, 0f, 1f, 0f,
+ 0f, 0f, 0f, 1f, 0f,
+ 0f, 0f, 0f, 1f, 0f,
+ 0f, 0f, 0f, 0f, 255f
+ )
+ )
+ canvas.drawBitmap(map, 0f, 0f, paint)
+ canvas.setBitmap(null)
+ return gainmapVisualizer
+}
+
class GainmapDecodeTest(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
private fun decode(mode: DecodeMode) {
@@ -71,7 +95,7 @@
}
}
- val gainmapContents = gainmapImage.gainmap!!.gainmapContents!!
+ val gainmapContents = gainmapImage.gainmap?.let { gainmapVisualizer(it) }
val sdrBitmap = gainmapImage.also { it.gainmap = null }
findViewById<ImageView>(R.id.sdr_source)!!.setImageBitmap(sdrBitmap)
@@ -80,7 +104,7 @@
findViewById<ImageView>(R.id.gainmap)!!.setImageBitmap(gainmapContents)
findViewById<TextView>(R.id.gainmap_label)!!.text =
- "Gainmap Size: ${gainmapContents.width}x${gainmapContents.height}"
+ "Gainmap Size: ${gainmapContents?.width ?: 0}x${gainmapContents?.height ?: 0}"
}
override fun onFinishInflate() {
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt
new file mode 100644
index 0000000..20984fa
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt
@@ -0,0 +1,116 @@
+/*
+ * 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.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.ImageDecoder
+import android.graphics.Matrix
+import android.util.AttributeSet
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GainmapTransformsTest(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
+
+ private val sourceImage = loadSample()
+
+ private fun loadSample(): Bitmap {
+ val source = ImageDecoder.createSource(resources.assets,
+ "gainmaps/${context.assets.list("gainmaps")!![0]}")
+
+ return ImageDecoder.decodeBitmap(source) { decoder, info, source ->
+ decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
+ }
+ }
+
+ private fun process(transform: (Bitmap) -> Bitmap) {
+ val result = transform(sourceImage)
+
+ val gainmapContents = result.gainmap?.let { gainmapVisualizer(it) }
+ val sdrBitmap = result.also { it.gainmap = null }
+
+ findViewById<ImageView>(R.id.sdr_source)!!.setImageBitmap(sdrBitmap)
+ findViewById<TextView>(R.id.sdr_label)!!.text =
+ "SDR Size: ${sdrBitmap.width}x${sdrBitmap.height}"
+
+ findViewById<ImageView>(R.id.gainmap)!!.setImageBitmap(gainmapContents)
+ findViewById<TextView>(R.id.gainmap_label)!!.text =
+ "Gainmap Size: ${gainmapContents?.width ?: 0}x${gainmapContents?.height ?: 0}"
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ val sourceInfo = findViewById<TextView>(R.id.source_info)!!
+ sourceInfo.text = "Original size ${sourceImage.width}x${sourceImage.height}"
+ process { it.copy(Bitmap.Config.ARGB_8888, false) }
+
+ findViewById<Button>(R.id.original)!!.setOnClickListener {
+ process { it.copy(Bitmap.Config.ARGB_8888, false) }
+ }
+
+ findViewById<Button>(R.id.scaled)!!.setOnClickListener {
+ process { Bitmap.createScaledBitmap(it, it.width / 3, it.height / 3, true) }
+ }
+
+ findViewById<Button>(R.id.rotate_90)!!.setOnClickListener {
+ process {
+ val width: Int = it.width
+ val height: Int = it.height
+
+ val m = Matrix()
+ m.setRotate(90.0f, (width / 2).toFloat(), (height / 2).toFloat())
+ Bitmap.createBitmap(it, 0, 0, width, height, m, false)
+ }
+ }
+
+ findViewById<Button>(R.id.rotate_90_scaled)!!.setOnClickListener {
+ process {
+ val width: Int = it.width
+ val height: Int = it.height
+
+ val m = Matrix()
+ m.setRotate(90.0f, (width / 2).toFloat(), (height / 2).toFloat())
+ m.preScale(.3f, .3f)
+ Bitmap.createBitmap(it, 0, 0, width, height, m, false)
+ }
+ }
+
+ findViewById<Button>(R.id.crop)!!.setOnClickListener {
+ process {
+ val width: Int = it.width
+ val height: Int = it.height
+ Bitmap.createBitmap(it, width / 2, height / 2,
+ width / 4, height / 4, null, false)
+ }
+ }
+
+ findViewById<Button>(R.id.crop_200)!!.setOnClickListener {
+ process {
+ val width: Int = it.width
+ val height: Int = it.height
+
+ val m = Matrix()
+ m.setRotate(200.0f, (width / 2).toFloat(), (height / 2).toFloat())
+ Bitmap.createBitmap(it, width / 2, height / 2,
+ width / 4, height / 4, m, false)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
index 9328b67..c60c519 100644
--- a/tests/UsbTests/Android.bp
+++ b/tests/UsbTests/Android.bp
@@ -29,7 +29,7 @@
static_libs: [
"frameworks-base-testutils",
"androidx.test.rules",
- "mockito-target-inline-minus-junit4",
+ "mockito-target-extended-minus-junit4",
"platform-test-annotations",
"services.core",
"services.net",
@@ -37,7 +37,12 @@
"truth-prebuilt",
"UsbManagerTestLib",
],
- jni_libs: ["libdexmakerjvmtiagent"],
+ jni_libs: [
+ // Required for ExtendedMockito
+ "libdexmakerjvmtiagent",
+ "libmultiplejvmtiagentsinterferenceagent",
+ "libstaticjvmtiagent",
+ ],
certificate: "platform",
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 210e3ea..c2d0f7c 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,23 +28,29 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.debug.AdbManagerInternal;
+import android.debug.AdbTransportType;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.HashMap;
import java.util.Locale;
@@ -68,6 +75,8 @@
private SharedPreferences mSharedPreferences;
@Mock
private SharedPreferences.Editor mEditor;
+ @Mock
+ private AdbManagerInternal mAdbManagerInternal;
private MockUsbHandler mUsbHandler;
@@ -83,6 +92,7 @@
private Map<String, String> mMockProperties;
private Map<String, Integer> mMockGlobalSettings;
+ private MockitoSession mStaticMockSession;
private class MockUsbHandler extends UsbDeviceManager.UsbHandler {
boolean mIsUsbTransferAllowed;
@@ -157,6 +167,10 @@
@Before
public void before() {
MockitoAnnotations.initMocks(this);
+ mStaticMockSession = ExtendedMockito.mockitoSession()
+ .mockStatic(LocalServices.class)
+ .strictness(Strictness.WARN)
+ .startMocking();
mMockProperties = new HashMap<>();
mMockGlobalSettings = new HashMap<>();
when(mSharedPreferences.edit()).thenReturn(mEditor);
@@ -164,6 +178,16 @@
mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
mUsbSettingsManager, mUsbPermissionManager);
+
+ when(LocalServices.getService(eq(AdbManagerInternal.class)))
+ .thenReturn(mAdbManagerInternal);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mStaticMockSession != null) {
+ mStaticMockSession.finishMocking();
+ }
}
@SmallTest
@@ -234,8 +258,8 @@
assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
assertEquals(mMockProperties.get(UsbDeviceManager.UsbHandler
.USB_PERSISTENT_CONFIG_PROPERTY), UsbManager.USB_FUNCTION_ADB);
- assertTrue(mUsbHandler.isAdbEnabled());
+ when(mAdbManagerInternal.isAdbEnabled(eq(AdbTransportType.USB))).thenReturn(true);
mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 1, 1));
assertTrue(mUsbHandler.mBroadcastedIntent.getBooleanExtra(UsbManager.USB_CONNECTED, false));
@@ -271,20 +295,6 @@
@SmallTest
@Test
- public void bootCompletedAdbEnabled() {
- mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY, "adb");
- mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
- InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
- mUsbSettingsManager, mUsbPermissionManager);
-
- sendBootCompleteMessages(mUsbHandler);
- assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
- assertEquals(mMockGlobalSettings.get(Settings.Global.ADB_ENABLED).intValue(), 1);
- assertTrue(mUsbHandler.isAdbEnabled());
- }
-
- @SmallTest
- @Test
public void userSwitchedDisablesMtp() {
mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
UsbManager.FUNCTION_MTP));
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 4123f80..960b57c 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -118,6 +118,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnManagementServiceTest {
+ private static final String CONTEXT_ATTRIBUTION_TAG = "VCN";
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2";
@@ -177,6 +178,7 @@
0 /* carrierId */,
0 /* profileClass */);
+ private final Context mMockContextWithoutAttributionTag = mock(Context.class);
private final Context mMockContext = mock(Context.class);
private final VcnManagementService.Dependencies mMockDeps =
mock(VcnManagementService.Dependencies.class);
@@ -202,6 +204,10 @@
private final IBinder mMockIBinder = mock(IBinder.class);
public VcnManagementServiceTest() throws Exception {
+ doReturn(mMockContext)
+ .when(mMockContextWithoutAttributionTag)
+ .createAttributionContext(CONTEXT_ATTRIBUTION_TAG);
+
setupSystemService(
mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
setupSystemService(
@@ -249,7 +255,7 @@
doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
setupMockedCarrierPrivilege(true);
- mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ mVcnMgmtSvc = new VcnManagementService(mMockContextWithoutAttributionTag, mMockDeps);
setupActiveSubscription(TEST_UUID_1);
doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();