Merge "Update top bar with new settings intent" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 935b2bb..ee381a4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1121,6 +1121,7 @@
"core/java/com/android/internal/os/SomeArgs.java",
"core/java/com/android/internal/util/BitwiseInputStream.java",
"core/java/com/android/internal/util/BitwiseOutputStream.java",
+ "core/java/com/android/internal/util/FunctionalUtils.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
"core/java/com/android/internal/util/Preconditions.java",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index fbc5c9d..90df19a 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -79,7 +79,7 @@
"sdk-dir",
"api-versions-jars-dir",
],
- previous_api: ":last-released-public-api",
+ previous_api: ":android.api.public.latest",
merge_annotations_dirs: [
"metalava-manual",
],
@@ -101,7 +101,7 @@
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) ",
+ args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
write_sdk_values: true,
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 8fd8c90..5052499 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -48,7 +48,6 @@
":opt-telephony-srcs",
":opt-net-voip-srcs",
":art-module-public-api-stubs-source",
- ":conscrypt.module.public.api.stubs.source",
":android_icu4j_public_api_files",
],
// TODO(b/147699819): remove below aidl includes.
@@ -58,7 +57,7 @@
libs: ["framework-internal-utils"],
installable: false,
annotations_enabled: true,
- previous_api: ":last-released-public-api",
+ previous_api: ":android.api.public.latest",
merge_annotations_dirs: [
"metalava-manual",
],
@@ -69,7 +68,10 @@
stubs_defaults {
name: "metalava-full-api-stubs-default",
defaults: ["metalava-base-api-stubs-default"],
- srcs: [":framework-updatable-sources"],
+ srcs: [
+ ":conscrypt.module.public.api.stubs.source",
+ ":framework-updatable-sources",
+ ],
sdk_version: "core_platform",
}
@@ -109,13 +111,13 @@
removed_api_file: "api/removed.txt",
},
last_released: {
- api_file: ":last-released-public-api",
- removed_api_file: "api/removed.txt",
+ api_file: ":android.api.public.latest",
+ removed_api_file: ":removed.api.public.latest",
baseline_file: ":public-api-incompatibilities-with-last-released",
},
api_lint: {
enabled: true,
- new_since: ":last-released-public-api",
+ new_since: ":android.api.public.latest",
baseline_file: "api/lint-baseline.txt",
},
},
@@ -151,13 +153,13 @@
removed_api_file: "api/system-removed.txt",
},
last_released: {
- api_file: ":last-released-system-api",
- removed_api_file: "api/system-removed.txt",
+ api_file: ":android.api.system.latest",
+ removed_api_file: ":removed.api.system.latest",
baseline_file: ":system-api-incompatibilities-with-last-released"
},
api_lint: {
enabled: true,
- new_since: ":last-released-system-api",
+ new_since: ":android.api.system.latest",
baseline_file: "api/system-lint-baseline.txt",
},
},
@@ -215,13 +217,13 @@
removed_api_file: "api/module-lib-removed.txt",
},
last_released: {
- api_file: ":last-released-module-lib-api",
- removed_api_file: "api/module-lib-removed.txt",
+ api_file: ":android.api.module-lib.latest",
+ removed_api_file: ":removed.api.module-lib.latest",
baseline_file: ":module-lib-api-incompatibilities-with-last-released"
},
api_lint: {
enabled: true,
- new_since: ":last-released-module-lib-api",
+ new_since: ":android.api.module-lib.latest",
baseline_file: "api/module-lib-lint-baseline.txt",
},
},
@@ -318,7 +320,7 @@
installable: false,
sdk_version: "core_platform",
annotations_enabled: true,
- previous_api: ":last-released-public-api",
+ previous_api: ":android.api.public.latest",
merge_annotations_dirs: [
"metalava-manual",
],
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 478cfc1..1b28913 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -25,9 +25,4 @@
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
</test>
-
- <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/data/local/CorePerfTests" />
- <option name="collect-on-run-ended-only" value="true" />
- </metrics_collector>
</configuration>
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
new file mode 100644
index 0000000..f02cbcf
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "WmPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ ],
+ test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
new file mode 100644
index 0000000..7198176
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.perftests.wm">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.perftests.utils.PerfTestActivity">
+ <intent-filter>
+ <action android:name="com.android.perftests.core.PERFTEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.wm"/>
+</manifest>
diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml
new file mode 100644
index 0000000..69d187f
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs WmPerfTests metric instrumentation.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-metric-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="WmPerfTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.wm" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/WmPerfTests" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
similarity index 95%
rename from apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 836e6b6..1667c165 100644
--- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -46,6 +46,7 @@
import org.junit.AfterClass;
import org.junit.Assume;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@@ -72,6 +73,12 @@
private long mMeasuredTimeNs;
+ /**
+ * Used to skip each test method if there is error. It cannot be raised in static setup because
+ * that will break the amount of target method count.
+ */
+ private static Exception sSetUpClassException;
+
@Parameterized.Parameter(0)
public int intervalBetweenOperations;
@@ -107,15 +114,21 @@
sRecentsIntent =
new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
} catch (Exception e) {
- Assume.assumeNoException(e);
+ sSetUpClassException = e;
}
}
@AfterClass
public static void tearDownClass() {
+ sSetUpClassException = null;
sUiAutomation.dropShellPermissionIdentity();
}
+ @Before
+ public void setUp() {
+ Assume.assumeNoException(sSetUpClassException);
+ }
+
/** Simulate the timing of touch. */
private void makeInterval() {
SystemClock.sleep(intervalBetweenOperations);
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
rename to apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
similarity index 100%
rename from apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
rename to apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
diff --git a/apex/Android.bp b/apex/Android.bp
index 67cd0d7..51e030b 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -74,6 +74,9 @@
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -93,6 +96,9 @@
api_file: "api/system-current.txt",
removed_api_file: "api/system-removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -147,6 +153,9 @@
api_file: "api/module-lib-current.txt",
removed_api_file: "api/module-lib-removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
@@ -173,6 +182,9 @@
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
},
+ api_lint: {
+ enabled: true,
+ },
},
dist: {
targets: ["sdk", "win_sdk"],
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index 3f254c0..0647d8a 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -307,8 +307,8 @@
* {@link #getRemainingLeaseQuotaBytes()} before trying to
* acquire a lease.
*
- * @see {@link #acquireLease(BlobHandle, int)}
- * @see {@link #acquireLease(BlobHandle, CharSequence)}
+ * @see #acquireLease(BlobHandle, int)
+ * @see #acquireLease(BlobHandle, CharSequence)
*/
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
@CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
@@ -367,8 +367,8 @@
* {@link #getRemainingLeaseQuotaBytes()} before trying to
* acquire a lease.
*
- * @see {@link #acquireLease(BlobHandle, int, long)}
- * @see {@link #acquireLease(BlobHandle, CharSequence)}
+ * @see #acquireLease(BlobHandle, int, long)
+ * @see #acquireLease(BlobHandle, CharSequence)
*/
public void acquireLease(@NonNull BlobHandle blobHandle, @NonNull CharSequence description,
@CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
@@ -420,8 +420,8 @@
* {@link #getRemainingLeaseQuotaBytes()} before trying to
* acquire a lease.
*
- * @see {@link #acquireLease(BlobHandle, int, long)}
- * @see {@link #acquireLease(BlobHandle, CharSequence, long)}
+ * @see #acquireLease(BlobHandle, int, long)
+ * @see #acquireLease(BlobHandle, CharSequence, long)
*/
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId)
throws IOException {
@@ -467,8 +467,8 @@
* {@link #getRemainingLeaseQuotaBytes()} before trying to
* acquire a lease.
*
- * @see {@link #acquireLease(BlobHandle, int)}
- * @see {@link #acquireLease(BlobHandle, CharSequence, long)}
+ * @see #acquireLease(BlobHandle, int)
+ * @see #acquireLease(BlobHandle, CharSequence, long)
*/
public void acquireLease(@NonNull BlobHandle blobHandle, @NonNull CharSequence description)
throws IOException {
diff --git a/apex/extservices/Android.bp b/apex/extservices/Android.bp
index 68350af..0c6c4c2 100644
--- a/apex/extservices/Android.bp
+++ b/apex/extservices/Android.bp
@@ -21,7 +21,7 @@
apex_defaults {
name: "com.android.extservices-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "current",
key: "com.android.extservices.key",
certificate: ":com.android.extservices.certificate",
apps: ["ExtServices"],
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index abf78c6..2312635 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -41,7 +41,7 @@
* system will execute this job on your application's {@link android.app.job.JobService}.
* You identify the service component that implements the logic for your job when you
* construct the JobInfo using
- * {@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}.
+ * {@link android.app.job.JobInfo.Builder#Builder(int,android.content.ComponentName)}.
* </p>
* <p>
* The framework will be intelligent about when it executes jobs, and attempt to batch
@@ -153,7 +153,7 @@
* method is ignored.
*
* @param jobId unique identifier for the job to be canceled, as supplied to
- * {@link JobInfo.Builder#JobInfo.Builder(int, android.content.ComponentName)
+ * {@link JobInfo.Builder#Builder(int, android.content.ComponentName)
* JobInfo.Builder(int, android.content.ComponentName)}.
*/
public abstract void cancel(int jobId);
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 6d9e3ed..887d82c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -45,6 +45,14 @@
boolean idle, int bucket, int reason);
/**
+ * Callback to inform listeners that the parole state has changed. This means apps are
+ * allowed to do work even if they're idle or in a low bucket.
+ */
+ public void onParoleStateChanged(boolean isParoleOn) {
+ // No-op by default
+ }
+
+ /**
* Optional callback to inform the listener that the app has transitioned into
* an active state due to user interaction.
*/
@@ -92,6 +100,11 @@
boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime);
+ /**
+ * @return true if currently app idle parole mode is on.
+ */
+ boolean isInParole();
+
int[] getIdleUidsForUser(int userId);
void setAppIdleAsync(String packageName, boolean idle, int userId);
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 d7c6ddb..d7be259 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
@@ -472,7 +472,7 @@
if (standbyBucket == RESTRICTED_INDEX) {
addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
} else {
- mReadyDynamicSatisfied = true;
+ mReadyDynamicSatisfied = false;
}
mLastSuccessfulRunTime = lastSuccessfulRunTime;
@@ -1132,8 +1132,8 @@
}
satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
- mReadyDynamicSatisfied =
- mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
+ mReadyDynamicSatisfied = mDynamicConstraints != 0
+ && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
FrameworkStatsLog.write_non_chained(
FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
@@ -1184,8 +1184,8 @@
}
mDynamicConstraints |= constraints;
- mReadyDynamicSatisfied =
- mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
+ mReadyDynamicSatisfied = mDynamicConstraints != 0
+ && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
}
/**
@@ -1196,8 +1196,8 @@
*/
private void removeDynamicConstraints(int constraints) {
mDynamicConstraints &= ~constraints;
- mReadyDynamicSatisfied =
- mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
+ mReadyDynamicSatisfied = mDynamicConstraints != 0
+ && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
}
public long getLastSuccessfulRunTime() {
@@ -1241,8 +1241,8 @@
break;
default:
satisfied |= constraint;
- mReadyDynamicSatisfied =
- mDynamicConstraints == (satisfied & mDynamicConstraints);
+ mReadyDynamicSatisfied = mDynamicConstraints != 0
+ && mDynamicConstraints == (satisfied & mDynamicConstraints);
break;
}
@@ -1262,8 +1262,8 @@
mReadyWithinQuota = oldValue;
break;
default:
- mReadyDynamicSatisfied =
- mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
+ mReadyDynamicSatisfied = mDynamicConstraints != 0
+ && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
break;
}
return toReturn;
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 24728dd..980372d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -214,8 +214,7 @@
private AppIdleHistory mAppIdleHistory;
@GuardedBy("mPackageAccessListeners")
- private ArrayList<AppIdleStateChangeListener>
- mPackageAccessListeners = new ArrayList<>();
+ private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
/** Whether we've queried the list of carrier privileged apps. */
@GuardedBy("mAppIdleLock")
@@ -235,6 +234,7 @@
static final int MSG_FORCE_IDLE_STATE = 4;
static final int MSG_CHECK_IDLE_STATES = 5;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
+ static final int MSG_PAROLE_STATE_CHANGED = 9;
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
@@ -293,6 +293,13 @@
* {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
*/
boolean mLinkCrossProfileApps;
+ /**
+ * Whether we should allow apps into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
+ * If false, any attempts to put an app into the bucket will put the app into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead.
+ */
+ private boolean mAllowRestrictedBucket;
private volatile boolean mAppIdleEnabled;
private boolean mIsCharging;
@@ -390,7 +397,16 @@
@VisibleForTesting
void setAppIdleEnabled(boolean enabled) {
- mAppIdleEnabled = enabled;
+ synchronized (mAppIdleLock) {
+ if (mAppIdleEnabled != enabled) {
+ final boolean oldParoleState = isInParole();
+ mAppIdleEnabled = enabled;
+ if (isInParole() != oldParoleState) {
+ postParoleStateChanged();
+ }
+ }
+ }
+
}
@Override
@@ -563,11 +579,23 @@
if (mIsCharging != isCharging) {
if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
mIsCharging = isCharging;
+ postParoleStateChanged();
}
}
}
@Override
+ public boolean isInParole() {
+ return !mAppIdleEnabled || mIsCharging;
+ }
+
+ private void postParoleStateChanged() {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
+ mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
+ mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
+ }
+
+ @Override
public void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
@@ -667,6 +695,10 @@
return;
}
final int oldBucket = app.currentBucket;
+ if (oldBucket == STANDBY_BUCKET_NEVER) {
+ // None of this should bring an app out of the NEVER bucket.
+ return;
+ }
int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
// Compute age-based bucket
@@ -722,11 +754,18 @@
Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
}
}
+ if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
+ newBucket = STANDBY_BUCKET_RARE;
+ // Leave the reason alone.
+ if (DEBUG) {
+ Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
+ }
+ }
if (DEBUG) {
Slog.d(TAG, " Old bucket=" + oldBucket
+ ", newBucket=" + newBucket);
}
- if (oldBucket < newBucket || predictionLate) {
+ if (oldBucket != newBucket || predictionLate) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
elapsedRealtime, newBucket, reason);
maybeInformListeners(packageName, userId, elapsedRealtime,
@@ -1176,8 +1215,8 @@
final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
final long nowElapsed = mInjector.elapsedRealtime();
- setAppStandbyBucket(packageName, userId, STANDBY_BUCKET_RESTRICTED, reason,
- nowElapsed, false);
+ final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
+ setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
}
@Override
@@ -1247,6 +1286,9 @@
Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
return;
}
+ if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
+ newBucket = STANDBY_BUCKET_RARE;
+ }
AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
@@ -1365,6 +1407,7 @@
Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
}
} else if (newBucket == STANDBY_BUCKET_RARE
+ && mAllowRestrictedBucket
&& getBucketForLocked(packageName, userId, elapsedRealtime)
== STANDBY_BUCKET_RESTRICTED) {
// Prediction doesn't think the app will be used anytime soon and
@@ -1502,6 +1545,15 @@
}
}
+ private void informParoleStateChanged() {
+ final boolean paroled = isInParole();
+ synchronized (mPackageAccessListeners) {
+ for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
+ listener.onParoleStateChanged(paroled);
+ }
+ }
+ }
+
@Override
public void flushToDisk(int userId) {
synchronized (mAppIdleLock) {
@@ -1697,6 +1749,8 @@
pw.println();
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
+ pw.print(" mAllowRestrictedBucket=");
+ pw.print(mAllowRestrictedBucket);
pw.print(" mIsCharging=");
pw.print(mIsCharging);
pw.println();
@@ -1798,6 +1852,12 @@
return mPowerWhitelistManager.isWhitelisted(packageName, false);
}
+ boolean isRestrictedBucketEnabled() {
+ return Global.getInt(mContext.getContentResolver(),
+ Global.ENABLE_RESTRICTED_BUCKET,
+ Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1;
+ }
+
File getDataSystemDirectory() {
return Environment.getDataSystemDirectory();
}
@@ -1920,6 +1980,11 @@
args.recycle();
break;
+ case MSG_PAROLE_STATE_CHANGED:
+ if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole());
+ informParoleStateChanged();
+ break;
+
case MSG_CHECK_PACKAGE_IDLE_STATE:
checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
mInjector.elapsedRealtime());
@@ -2031,6 +2096,8 @@
final ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
+ cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET),
+ false, this);
cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
false, this);
}
@@ -2129,6 +2196,8 @@
mLinkCrossProfileApps = mParser.getBoolean(
KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
+
+ mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled();
}
// Check if app_idle_enabled has changed. Do this after getting the rest of the settings
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 34fe228..3bc4f7b 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -49,6 +49,7 @@
"com.android.media",
"test_com.android.media",
],
+ min_sdk_version: "29",
}
filegroup {
@@ -92,6 +93,7 @@
// TODO(b/135922046) remove this
include_dirs: ["frameworks/base/core/java"],
},
+ dist: { dest: "framework-media.txt" },
}
droidstubs {
@@ -100,6 +102,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-stubs-defaults-publicapi",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.public.latest",
+ removed_api_file: ":framework-media-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -108,6 +119,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-stubs-defaults-systemapi",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.system.latest",
+ removed_api_file: ":framework-media-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -116,6 +136,15 @@
"framework-media-stubs-srcs-defaults",
"framework-module-api-defaults-module_libs_api",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-media.api.module-lib.latest",
+ removed_api_file: ":framework-media-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-media.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -130,18 +159,21 @@
name: "framework-media-stubs-publicapi",
srcs: [":framework-media-stubs-srcs-publicapi"],
defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+ dist: { dest: "framework-media.jar" },
}
java_library {
name: "framework-media-stubs-systemapi",
srcs: [":framework-media-stubs-srcs-systemapi"],
defaults: ["framework-module-stubs-lib-defaults-systemapi"],
+ dist: { dest: "framework-media.jar" },
}
java_library {
name: "framework-media-stubs-module_libs_api",
srcs: [":framework-media-stubs-srcs-module_libs_api"],
defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
+ dist: { dest: "framework-media.jar" },
}
java_library {
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index d22e998..a9ed6d8 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -1288,7 +1288,11 @@
}
@Override
- public int sampleData(DataReader input, int length, boolean allowEndOfInput)
+ public int sampleData(
+ DataReader input,
+ int length,
+ boolean allowEndOfInput,
+ @SampleDataPart int sampleDataPart)
throws IOException {
mScratchDataReaderAdapter.setDataReader(input, length);
long positionBeforeReading = mScratchDataReaderAdapter.getPosition();
@@ -1297,7 +1301,8 @@
}
@Override
- public void sampleData(ParsableByteArray data, int length) {
+ public void sampleData(
+ ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
try {
mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter);
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index fc9052e..68c27a8 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -46,6 +46,7 @@
name: "framework-permission-stubs-defaults",
srcs: [ ":framework-permission-sources" ],
libs: [ "framework-annotations-lib" ],
+ dist: { dest: "framework-permission.txt" },
}
droidstubs {
@@ -54,6 +55,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.public.latest",
+ removed_api_file: ":framework-permission-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -62,6 +72,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.system.latest",
+ removed_api_file: ":framework-permission-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -70,6 +89,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-permission-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-permission.api.module-lib.latest",
+ removed_api_file: ":framework-permission-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-permission.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -84,16 +112,19 @@
name: "framework-permission-stubs-publicapi",
srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+ dist: { dest: "framework-permission.jar" },
}
java_library {
name: "framework-permission-stubs-systemapi",
srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
defaults: ["framework-module-stubs-lib-defaults-systemapi"],
+ dist: { dest: "framework-permission.jar" },
}
java_library {
name: "framework-permission-stubs-module_libs_api",
srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
+ dist: { dest: "framework-permission.jar" },
}
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
index 2eb7e99..6144976 100644
--- a/apex/permission/service/Android.bp
+++ b/apex/permission/service/Android.bp
@@ -41,12 +41,23 @@
name: "service-permission-stubs-srcs",
srcs: [ ":service-permission-sources" ],
defaults: ["service-module-stubs-srcs-defaults"],
- visibility: ["//visibility:private"]
+ check_api: {
+ last_released: {
+ api_file: ":service-permission.api.system-server.latest",
+ removed_api_file: ":service-permission-removed.api.system-server.latest",
+ },
+ api_lint: {
+ new_since: ":service-permission.api.system-server.latest",
+ },
+ },
+ visibility: ["//visibility:private"],
+ dist: { dest: "service-permission.txt" },
}
java_library {
name: "service-permission-stubs",
srcs: [":service-permission-stubs-srcs"],
defaults: ["service-module-stubs-defaults"],
- visibility: ["//frameworks/base/services/core"]
+ visibility: ["//frameworks/base/services/core"],
+ dist: { dest: "service-permission.jar" },
}
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index fc26e08..dbb5bd3d 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -22,6 +22,7 @@
binaries: [ "derive_sdk" ],
prebuilts: [ "cur_sdkinfo" ],
manifest: "manifest.json",
+ min_sdk_version: "current",
}
apex_defaults {
diff --git a/apex/sdkextensions/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp
index cf49902..41eae09 100644
--- a/apex/sdkextensions/derive_sdk/Android.bp
+++ b/apex/sdkextensions/derive_sdk/Android.bp
@@ -20,14 +20,13 @@
],
proto: {
type: "lite",
+ static: true,
},
- sdk_version: "current",
+ min_sdk_version: "current",
+ shared_libs: ["liblog"],
+ // static c++/libbase for smaller size
stl: "c++_static",
- shared_libs: [ "liblog" ],
- static_libs: [
- "libbase_ndk",
- "libprotobuf-cpp-lite-ndk",
- ],
+ static_libs: ["libbase"],
}
cc_binary {
@@ -45,7 +44,8 @@
compile_multilib: "prefer32",
stem: "derive_sdk",
apex_available: [ "test_com.android.sdkext" ],
- visibility: [ "//frameworks/base/apex/sdkextensions/testing" ]
+ visibility: [ "//frameworks/base/apex/sdkextensions/testing" ],
+ installable: false,
}
prebuilt_etc {
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 3eabb88..14e23ed 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -48,6 +48,7 @@
name: "framework-sdkextensions-stubs-defaults",
srcs: [ ":framework-sdkextensions-sources" ],
libs: [ "framework-annotations-lib" ],
+ dist: { dest: "framework-sdkextensions.txt" },
}
droidstubs {
@@ -55,7 +56,16 @@
defaults: [
"framework-module-stubs-defaults-publicapi",
"framework-sdkextensions-stubs-defaults",
- ]
+ ],
+ check_api: {
+ last_released: {
+ api_file: ":framework-sdkextensions.api.public.latest",
+ removed_api_file: ":framework-sdkextensions-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-sdkextensions.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -63,7 +73,16 @@
defaults: [
"framework-module-stubs-defaults-systemapi",
"framework-sdkextensions-stubs-defaults",
- ]
+ ],
+ check_api: {
+ last_released: {
+ api_file: ":framework-sdkextensions.api.system.latest",
+ removed_api_file: ":framework-sdkextensions-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-sdkextensions.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -71,7 +90,16 @@
defaults: [
"framework-module-api-defaults-module_libs_api",
"framework-sdkextensions-stubs-defaults",
- ]
+ ],
+ check_api: {
+ last_released: {
+ api_file: ":framework-sdkextensions.api.module-lib.latest",
+ removed_api_file: ":framework-sdkextensions-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-sdkextensions.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -79,7 +107,7 @@
defaults: [
"framework-module-stubs-defaults-module_libs_api",
"framework-sdkextensions-stubs-defaults",
- ]
+ ],
}
java_library {
@@ -89,7 +117,8 @@
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ]
+ ],
+ dist: { dest: "framework-sdkextensions.jar" },
}
java_library {
@@ -99,7 +128,8 @@
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ]
+ ],
+ dist: { dest: "framework-sdkextensions.jar" },
}
java_library {
@@ -109,5 +139,6 @@
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ]
+ ],
+ dist: { dest: "framework-sdkextensions.jar" },
}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 6f29141..9f5d933 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -84,6 +84,7 @@
"framework-annotations-lib",
],
sdk_version: "system_current",
+ dist: { dest: "framework-statsd.txt" },
}
droidstubs {
@@ -92,6 +93,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-statsd-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.public.latest",
+ removed_api_file: ":framework-statsd-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -100,7 +110,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-statsd-stubs-srcs-defaults",
],
-
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.system.latest",
+ removed_api_file: ":framework-statsd-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -109,6 +127,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-statsd-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-statsd.api.module-lib.latest",
+ removed_api_file: ":framework-statsd-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-statsd.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -127,6 +154,7 @@
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
],
+ dist: { dest: "framework-statsd.jar" },
}
java_library {
@@ -137,6 +165,7 @@
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
],
+ dist: { dest: "framework-statsd.jar" },
}
java_library {
@@ -149,6 +178,7 @@
"//frameworks/opt/net/wifi/service", // wifi service
"//packages/providers/MediaProvider", // MediaProvider apk
],
+ dist: { dest: "framework-statsd.jar" },
}
android_test {
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 7fbfc43..d1b7d8d 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -28,7 +28,6 @@
import android.os.IPullAtomCallback;
import android.os.IPullAtomResultReceiver;
import android.os.IStatsManagerService;
-import android.os.IStatsd;
import android.os.RemoteException;
import android.os.StatsFrameworkInitializer;
import android.util.AndroidException;
@@ -57,9 +56,6 @@
private final Context mContext;
@GuardedBy("sLock")
- private IStatsd mService;
-
- @GuardedBy("sLock")
private IStatsManagerService mStatsManagerService;
/**
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 93e6c10..5cf5e0b 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,11 +54,11 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
@@ -112,17 +112,8 @@
private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
private final CompanionHandler mHandler;
- // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This
- // and the flag mSentBootComplete below is used for synchronization to ensure that the boot
- // complete signal is only ever sent once to statsd. Two signals are needed because
- // #sayHiToStatsd can be called from both statsd and #onBootPhase
- // PHASE_THIRD_PARTY_APPS_CAN_START.
- @GuardedBy("sStatsdLock")
- private boolean mBootCompleted = false;
- // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete
- // signal is only ever sent once.
- @GuardedBy("sStatsdLock")
- private boolean mSentBootComplete = false;
+ // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle.
+ private AtomicBoolean mBootCompleted = new AtomicBoolean(false);
public StatsCompanionService(Context context) {
super();
@@ -607,27 +598,35 @@
// Statsd related code
/**
- * Fetches the statsd IBinder service. This is a blocking call.
+ * Fetches the statsd IBinder service. This is a blocking call that always refetches statsd
+ * instead of returning the cached sStatsd.
* Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
* the cached sStatsd via {@link #getStatsdNonblocking()}.
*/
- private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
- .getStatsServiceManager()
- .getStatsdServiceRegisterer()
- .get());
- if (sStatsd != null) {
- try {
- sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
- statsdNotReadyLocked();
- }
+ private IStatsd fetchStatsdServiceLocked() {
+ sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
+ return sStatsd;
+ }
+
+ private void registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
+ StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient(statsd, receivers);
+
+ try {
+ statsd.asBinder().linkToDeath(deathRecipient, /*flags=*/0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath (StatsdDeathRecipient) failed");
+ // Statsd has already died. Unregister receivers ourselves.
+ for (BroadcastReceiver receiver : receivers) {
+ mContext.unregisterReceiver(receiver);
+ }
+ synchronized (sStatsdLock) {
+ if (statsd == sStatsd) {
+ statsdNotReadyLocked();
}
}
- return sStatsd;
}
}
@@ -648,22 +647,23 @@
* statsd.
*/
private void sayHiToStatsd() {
- if (getStatsdNonblocking() != null) {
- Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
- new IllegalStateException(
- "sStatsd is not null when being fetched"));
- return;
+ IStatsd statsd;
+ synchronized (sStatsdLock) {
+ if (sStatsd != null && sStatsd.asBinder().isBinderAlive()) {
+ Log.e(TAG, "statsd has already been fetched before",
+ new IllegalStateException("IStatsd object should be null or dead"));
+ return;
+ }
+ statsd = fetchStatsdServiceLocked();
}
- StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
- IStatsd statsd = fetchStatsdService(deathRecipient);
+
if (statsd == null) {
- Log.i(TAG,
- "Could not yet find statsd to tell it that StatsCompanion is "
- + "alive.");
+ Log.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
return;
}
- mStatsManagerService.statsdReady(statsd);
+
if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ mStatsManagerService.statsdReady(statsd);
try {
statsd.statsCompanionReady();
@@ -682,8 +682,7 @@
mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
// Setup receiver for user initialize (which happens once for a new user)
- // and
- // if a user is removed.
+ // and if a user is removed.
filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
@@ -691,27 +690,20 @@
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(
- shutdownEventReceiver, filter, null, null);
+ mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null);
- // Only add the receivers if the registration is successful.
- deathRecipient.addRegisteredBroadcastReceivers(
- List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+ // Register death recipient.
+ List<BroadcastReceiver> broadcastReceivers =
+ List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver);
+ registerStatsdDeathRecipient(statsd, broadcastReceivers);
- // Used so we can call statsd.bootComplete() outside of the lock.
- boolean shouldSendBootComplete = false;
- synchronized (sStatsdLock) {
- if (mBootCompleted && !mSentBootComplete) {
- mSentBootComplete = true;
- shouldSendBootComplete = true;
- }
- }
- if (shouldSendBootComplete) {
+ // Tell statsd that boot has completed. The signal may have already been sent, but since
+ // the signal-receiving function is idempotent, that's ok.
+ if (mBootCompleted.get()) {
statsd.bootCompleted();
}
- // Pull the latest state of UID->app name, version mapping when
- // statsd starts.
+ // Pull the latest state of UID->app name, version mapping when statsd starts.
informAllUids(mContext);
Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
@@ -722,18 +714,16 @@
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
- private List<BroadcastReceiver> mReceiversToUnregister;
+ private final IStatsd mStatsd;
+ private final List<BroadcastReceiver> mReceiversToUnregister;
- StatsdDeathRecipient() {
- mReceiversToUnregister = new ArrayList<>();
+ StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
+ mStatsd = statsd;
+ mReceiversToUnregister = receivers;
}
- public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
- synchronized (sStatsdLock) {
- mReceiversToUnregister.addAll(receivers);
- }
- }
-
+ // It is possible for binderDied to be called after a restarted statsd calls statsdReady,
+ // but that's alright because the code does not assume an ordering of the two calls.
@Override
public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -762,13 +752,19 @@
}
}
}
- // We only unregister in binder death becaseu receivers can only be unregistered
- // once, or an IllegalArgumentException is thrown.
+
+ // Unregister receivers on death because receivers can only be unregistered once.
+ // Otherwise, an IllegalArgumentException is thrown.
for (BroadcastReceiver receiver: mReceiversToUnregister) {
mContext.unregisterReceiver(receiver);
}
- statsdNotReadyLocked();
- mSentBootComplete = false;
+
+ // It's possible for statsd to have restarted and called statsdReady, causing a new
+ // sStatsd binder object to be fetched, before the binderDied callback runs. Only
+ // call #statsdNotReadyLocked if that hasn't happened yet.
+ if (mStatsd == sStatsd) {
+ statsdNotReadyLocked();
+ }
}
}
}
@@ -779,19 +775,12 @@
}
void bootCompleted() {
+ mBootCompleted.set(true);
IStatsd statsd = getStatsdNonblocking();
- synchronized (sStatsdLock) {
- mBootCompleted = true;
- if (mSentBootComplete) {
- // do not send a boot complete a second time.
- return;
- }
- if (statsd == null) {
- // Statsd is not yet ready.
- // Delay the boot completed ping to {@link #sayHiToStatsd()}
- return;
- }
- mSentBootComplete = true;
+ if (statsd == null) {
+ // Statsd is not yet ready.
+ // Delay the boot completed ping to {@link #sayHiToStatsd()}
+ return;
}
try {
statsd.bootCompleted();
@@ -808,8 +797,7 @@
}
synchronized (sStatsdLock) {
- writer.println(
- "Number of configuration files deleted: " + mDeletedFiles.size());
+ writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
if (mDeletedFiles.size() > 0) {
writer.println(" timestamp, deleted file name");
}
@@ -817,8 +805,7 @@
SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
for (Long elapsedMillis : mDeletedFiles.keySet()) {
long deletionMillis = lastBootMillis + elapsedMillis;
- writer.println(
- " " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
+ writer.println(" " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
}
}
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 90764b0..97846f2 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -172,6 +172,10 @@
public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
int[] additiveFields, IPullAtomCallback pullerCallback) {
enforceRegisterStatsPullAtomPermission();
+ if (pullerCallback == null) {
+ Log.w(TAG, "Puller callback is null for atom " + atomTag);
+ return;
+ }
int callingUid = Binder.getCallingUid();
PullerKey key = new PullerKey(callingUid, atomTag);
PullerValue val =
diff --git a/api/current.txt b/api/current.txt
index 3f8bee9..467aa32 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -290,7 +290,7 @@
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowEmbedded = 16843765; // 0x10103f5
- field public static final int allowNativeHeapPointerTagging = 16844307; // 0x1010613
+ field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -326,7 +326,7 @@
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
- field public static final int autoRevokePermissions = 16844309; // 0x1010615
+ field public static final int autoRevokePermissions = 16844307; // 0x1010613
field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
@@ -391,7 +391,7 @@
field public static final int canRequestFingerprintGestures = 16844109; // 0x101054d
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
- field public static final int canTakeScreenshot = 16844304; // 0x1010610
+ field public static final int canTakeScreenshot = 16844303; // 0x101060f
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
field public static final int cantSaveState = 16844142; // 0x101056e
field @Deprecated public static final int capitalize = 16843113; // 0x1010169
@@ -486,7 +486,7 @@
field public static final int countDown = 16844059; // 0x101051b
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
- field public static final int crossProfile = 16844303; // 0x101060f
+ field public static final int crossProfile = 16844302; // 0x101060e
field public static final int cursorVisible = 16843090; // 0x1010152
field public static final int customNavigationLayout = 16843474; // 0x10102d2
field public static final int customTokens = 16843579; // 0x101033b
@@ -708,7 +708,7 @@
field public static final int gravity = 16842927; // 0x10100af
field public static final int gridViewStyle = 16842865; // 0x1010071
field public static final int groupIndicator = 16843019; // 0x101010b
- field public static final int gwpAsanMode = 16844312; // 0x1010618
+ field public static final int gwpAsanMode = 16844310; // 0x1010616
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
@@ -953,7 +953,7 @@
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
- field public static final int mimeGroup = 16844311; // 0x1010617
+ field public static final int mimeGroup = 16844309; // 0x1010615
field public static final int mimeType = 16842790; // 0x1010026
field public static final int min = 16844089; // 0x1010539
field public static final int minAspectRatio = 16844187; // 0x101059b
@@ -1082,7 +1082,7 @@
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
- field public static final int preserveLegacyExternalStorage = 16844310; // 0x1010616
+ field public static final int preserveLegacyExternalStorage = 16844308; // 0x1010614
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
@@ -1345,7 +1345,7 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
- field public static final int supportsInlineSuggestions = 16844302; // 0x101060e
+ field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
@@ -35870,7 +35870,7 @@
field public static final int O_MR1 = 27; // 0x1b
field public static final int P = 28; // 0x1c
field public static final int Q = 29; // 0x1d
- field public static final int R = 10000; // 0x2710
+ field public static final int R = 30; // 0x1e
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/api/removed.txt b/api/removed.txt
index cddccb3..e7e9677 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,12 +1,4 @@
// Signature format: 2.0
-package android {
-
- public static final class R.attr {
- field public static final int featureId = 16844301; // 0x101060d
- }
-
-}
-
package android.app {
public class ActivityManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index c5d319c..f07ebaf 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -256,10 +256,10 @@
public static final class R.attr {
field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
field public static final int isVrOnly = 16844152; // 0x1010578
- field public static final int minExtensionVersion = 16844306; // 0x1010612
+ field public static final int minExtensionVersion = 16844305; // 0x1010611
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
- field public static final int sdkVersion = 16844305; // 0x1010611
+ field public static final int sdkVersion = 16844304; // 0x1010610
field public static final int supportsAmbientMode = 16844173; // 0x101058d
field public static final int userRestriction = 16844164; // 0x1010584
}
@@ -291,8 +291,8 @@
public static final class R.string {
field public static final int config_defaultAssistant = 17039393; // 0x1040021
field public static final int config_defaultBrowser = 17039394; // 0x1040022
- field public static final int config_defaultCallRedirection = 17039400; // 0x1040028
- field public static final int config_defaultCallScreening = 17039401; // 0x1040029
+ field public static final int config_defaultCallRedirection = 17039397; // 0x1040025
+ field public static final int config_defaultCallScreening = 17039398; // 0x1040026
field public static final int config_defaultDialer = 17039395; // 0x1040023
field public static final int config_defaultSms = 17039396; // 0x1040024
field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
@@ -301,7 +301,7 @@
field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
- field public static final int config_systemGallery = 17039402; // 0x104002a
+ field public static final int config_systemGallery = 17039399; // 0x1040027
}
public static final class R.style {
diff --git a/api/test-current.txt b/api/test-current.txt
index 44fb630..46049bd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38,7 +38,7 @@
public static final class R.string {
field public static final int config_defaultAssistant = 17039393; // 0x1040021
field public static final int config_defaultDialer = 17039395; // 0x1040023
- field public static final int config_systemGallery = 17039402; // 0x104002a
+ field public static final int config_systemGallery = 17039399; // 0x1040027
}
}
@@ -431,6 +431,7 @@
}
public class DreamManager {
+ method @RequiresPermission("android.permission.READ_DREAM_STATE") public boolean isDreaming();
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void setActiveDream(@NonNull android.content.ComponentName);
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void startDream(@NonNull android.content.ComponentName);
method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream();
@@ -4966,6 +4967,11 @@
method @Nullable public static AutoCloseable startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>);
}
+ public abstract class Window {
+ method @Nullable public android.view.View getNavigationBarBackgroundView();
+ method @Nullable public android.view.View getStatusBarBackgroundView();
+ }
+
public interface WindowManager extends android.view.ViewManager {
method public default void setShouldShowIme(int, boolean);
method public default void setShouldShowSystemDecors(int, boolean);
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 9f4f314..ad4de0a 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -5,4 +5,4 @@
disabled
oneshot
ioprio rt 0
- writepid /dev/stune/top-app/tasks
+ task_profiles MaxPerformance
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index bd9f7a5..a65f5f7 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -343,9 +343,11 @@
if (!utf8Args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, utf8Args);
}
+
if (!utf8Args[0].compare(String8("send-active-configs"))) {
return cmd_trigger_active_config_broadcast(out, utf8Args);
}
+
if (!utf8Args[0].compare(String8("data-subscribe"))) {
{
std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 674978b5..504890f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -427,6 +427,7 @@
AccessibilityShortcutReported accessibility_shortcut_reported =
266 [(module) = "framework"];
AccessibilityServiceReported accessibility_service_reported = 267 [(module) = "settings"];
+ DocsUIDragAndDropReported docs_ui_drag_and_drop_reported = 268 [(module) = "docsui"];
SdkExtensionStatus sdk_extension_status = 354;
// StatsdStats tracks platform atoms with ids upto 500.
@@ -3020,14 +3021,14 @@
optional string component_name = 11;
// (x, y) coordinate and the index information of the target on the container
- optional int32 grid_x = 12;
- optional int32 grid_y = 13;
- optional int32 page_id = 14;
+ optional int32 grid_x = 12 [default = -1];
+ optional int32 grid_y = 13 [default = -1];
+ optional int32 page_id = 14 [default = -2];
// e.g., folder icon's (x, y) location and index information on the workspace
- optional int32 grid_x_parent = 15;
- optional int32 grid_y_parent = 16;
- optional int32 page_id_parent = 17;
+ optional int32 grid_x_parent = 15 [default = -1];
+ optional int32 grid_y_parent = 16 [default = -1];
+ optional int32 page_id_parent = 17 [default = -2];
// e.g., SEARCHBOX_ALLAPPS, FOLDER_WORKSPACE
optional int32 hierarchy = 18;
@@ -3035,7 +3036,7 @@
optional bool is_work_profile = 19;
// Used to store the predicted rank of the target
- optional int32 rank = 20;
+ optional int32 rank = 20 [default = -1];
// e.g., folderLabelState can be captured in the following two fields
optional int32 from_state = 21;
@@ -3043,6 +3044,9 @@
// e.g., autofilled or suggested texts that are not user entered
optional string edittext = 23;
+
+ // e.g., number of contents inside a container (e.g., icons inside a folder)
+ optional int32 cardinality = 24;
}
/**
@@ -3063,22 +3067,34 @@
optional string component_name = 6;
// (x, y) coordinate and the index information of the target on the container
- optional int32 grid_x = 7;
- optional int32 grid_y = 8;
- optional int32 page_id = 9;
+ optional int32 grid_x = 7 [default = -1];
+ optional int32 grid_y = 8 [default = -1];
+ optional int32 page_id = 9 [default = -2];
// e.g., folder icon's (x, y) location and index information on the workspace
- optional int32 grid_x_parent = 10;
- optional int32 grid_y_parent = 11;
- optional int32 page_id_parent = 12;
+ // e.g., when used with widgets target, use these values for (span_x, span_y)
+ optional int32 grid_x_parent = 10 [default = -1];
+ optional int32 grid_y_parent = 11 [default = -1];
+ optional int32 page_id_parent = 12 [default = -2];
- // e.g., WORKSPACE, HOTSEAT, FOLDER_WORKSPACE, FOLDER_HOTSEAT
+ // UNKNOWN = 0
+ // HOTSEAT = 1
+ // WORKSPACE = 2
+ // FOLDER_HOTSEAT = 3
+ // FOLDER_WORKSPACE = 4
optional int32 hierarchy = 13;
optional bool is_work_profile = 14;
// e.g., PIN, WIDGET TRAY, APPS TRAY, PREDICTION
optional int32 origin = 15;
+
+ // e.g., number of icons inside a folder
+ optional int32 cardinality = 16;
+
+ // e.g., (x, y) span of the widget inside homescreen grid system
+ optional int32 span_x = 17 [default = 1];
+ optional int32 span_y = 18 [default = 1];
}
/**
@@ -4885,8 +4901,6 @@
optional int64 tx_bytes = 4;
optional int64 tx_packets = 5;
-
- optional int32 rat_type = 6;
}
/**
@@ -4909,8 +4923,6 @@
optional int64 tx_bytes = 5;
optional int64 tx_packets = 6;
-
- optional int32 rat_type = 7;
}
/**
@@ -5698,7 +5710,7 @@
optional AggStats rss = 8;
}
-// Next Tag: 7
+// Next Tag: 8
message ProcessStatsProto {
// Name of process.
optional string process = 1;
@@ -5725,6 +5737,25 @@
// Total time process has been running... screen_state, memory_state, and process_state
// will not be set.
optional ProcessStatsStateProto total_running_state = 6;
+
+ // Association data for this process in this state;
+ // each entry here is one association.
+ repeated ProcessStatsAssociationProto assocs = 7;
+}
+
+// Next Tag: 5
+message ProcessStatsAssociationProto {
+ // Procss Name of the associated process (client process of service binding)
+ optional string assoc_process_name = 1;
+
+ // Package Name of the associated package (client package of service binding)
+ optional string assoc_package_name = 2;
+
+ // Total count of the times this association (service binding) appeared.
+ optional int32 total_count = 3;
+
+ // Uptime total duration in seconds this association (service binding) was around.
+ optional int32 total_duration_secs = 4;
}
message PackageServiceOperationStatsProto {
@@ -6481,6 +6512,15 @@
optional int32 repeatedly_pick_times = 7;
}
+/** Logs the drag and drop of files.
+
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIDragAndDropReported {
+ optional bool drag_initiated_from_docsui = 1;
+}
+
/**
* Logs when an app's memory is compacted.
*
@@ -9086,6 +9126,9 @@
// Whether the call was performed while roaming.
optional bool is_roaming = 24;
+
+ // A random number used as the dimension field to pull multiple atoms.
+ optional int32 dimension = 25;
}
/**
@@ -9334,6 +9377,8 @@
// Return_code 1 indicates success.
// For full list, see frameworks/base/core/java/android/content/pm/PackageManager.java
optional int32 return_code = 4;
+ // Total size of the APKs installed for this package
+ optional int64 apks_size_bytes = 5;
}
/**
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index 3618bb0..78e6f09 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -86,6 +86,7 @@
// in unit tests. In process calls are not oneway.
Status status = mCallback->onPullAtom(mTagId, resultReceiver);
if (!status.isOk()) {
+ StatsdStats::getInstance().notePullBinderCallFailed(mTagId);
return false;
}
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 5192ddf..829a603 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -82,6 +82,11 @@
mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId, mAdditiveFields);
}
+ if (mCachedData.empty()) {
+ VLOG("Data pulled is empty");
+ StatsdStats::getInstance().noteEmptyData(mTagId);
+ }
+
(*data) = mCachedData;
return mHasGoodData;
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index cfd5d14..1a52eb9 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -111,12 +111,14 @@
if (uidProviderIt == mPullUidProviders.end()) {
ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId,
configKey.ToString().c_str());
+ StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
return false;
}
sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote();
if (pullUidProvider == nullptr) {
ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId,
configKey.ToString().c_str());
+ StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
return false;
}
uids = pullUidProvider->getPullAtomUids(tagId);
@@ -140,6 +142,7 @@
return ret;
}
}
+ StatsdStats::getInstance().notePullerNotFound(tagId);
ALOGW("StatsPullerManager: Unknown tagId %d", tagId);
return false; // Return early since we don't know what to pull.
} else {
@@ -288,10 +291,7 @@
for (const auto& pullInfo : needToPull) {
vector<shared_ptr<LogEvent>> data;
bool pullSuccess = PullLocked(pullInfo.first->atomTag, pullInfo.first->configKey, &data);
- if (pullSuccess) {
- StatsdStats::getInstance().notePullDelay(pullInfo.first->atomTag,
- getElapsedRealtimeNs() - elapsedTimeNs);
- } else {
+ if (!pullSuccess) {
VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
}
@@ -354,6 +354,11 @@
std::lock_guard<std::mutex> _l(mLock);
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
+ if (callback == nullptr) {
+ ALOGW("SetPullAtomCallback called with null callback for atom %d.", atomTag);
+ return;
+ }
+
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
int64_t actualCoolDownNs = coolDownNs < kMinCoolDownNs ? kMinCoolDownNs : coolDownNs;
int64_t actualTimeoutNs = timeoutNs > kMaxTimeoutNs ? kMaxTimeoutNs : timeoutNs;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 46f5dbd..c027fff 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -472,14 +472,19 @@
mPulledAtomStats[atomId].pullFailed++;
}
-void StatsdStats::noteStatsCompanionPullFailed(int atomId) {
+void StatsdStats::notePullUidProviderNotFound(int atomId) {
lock_guard<std::mutex> lock(mLock);
- mPulledAtomStats[atomId].statsCompanionPullFailed++;
+ mPulledAtomStats[atomId].pullUidProviderNotFound++;
}
-void StatsdStats::noteStatsCompanionPullBinderTransactionFailed(int atomId) {
+void StatsdStats::notePullerNotFound(int atomId) {
lock_guard<std::mutex> lock(mLock);
- mPulledAtomStats[atomId].statsCompanionPullBinderTransactionFailed++;
+ mPulledAtomStats[atomId].pullerNotFound++;
+}
+
+void StatsdStats::notePullBinderCallFailed(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].binderCallFailCount++;
}
void StatsdStats::noteEmptyData(int atomId) {
@@ -608,6 +613,7 @@
for (auto& pullStats : mPulledAtomStats) {
pullStats.second.totalPull = 0;
pullStats.second.totalPullFromCache = 0;
+ pullStats.second.minPullIntervalSec = LONG_MAX;
pullStats.second.avgPullTimeNs = 0;
pullStats.second.maxPullTimeNs = 0;
pullStats.second.numPullTime = 0;
@@ -617,9 +623,13 @@
pullStats.second.dataError = 0;
pullStats.second.pullTimeout = 0;
pullStats.second.pullExceedMaxDelay = 0;
+ pullStats.second.pullFailed = 0;
+ pullStats.second.pullUidProviderNotFound = 0;
+ pullStats.second.pullerNotFound = 0;
pullStats.second.registeredCount = 0;
pullStats.second.unregisteredCount = 0;
pullStats.second.atomErrorCount = 0;
+ pullStats.second.binderCallFailCount = 0;
}
mAtomMetricStats.clear();
mActivationBroadcastGuardrailStats.clear();
@@ -764,14 +774,16 @@
" (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
"nanos)%lld, "
" (max pull delay nanos)%lld, (data error)%ld\n"
- " (pull timeout)%ld, (pull exceed max delay)%ld\n"
- " (registered count) %ld, (unregistered count) %ld\n"
+ " (pull timeout)%ld, (pull exceed max delay)%ld"
+ " (no uid provider count)%ld, (no puller found count)%ld\n"
+ " (registered count) %ld, (unregistered count) %ld"
" (atom error count) %d\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.pullFailed, (long)pair.second.minPullIntervalSec,
(long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs,
(long long)pair.second.avgPullDelayNs, (long long)pair.second.maxPullDelayNs,
pair.second.dataError, pair.second.pullTimeout, pair.second.pullExceedMaxDelay,
+ pair.second.pullUidProviderNotFound, pair.second.pullerNotFound,
pair.second.registeredCount, pair.second.unregisteredCount,
pair.second.atomErrorCount);
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 805281c..3d0eeb8 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -371,21 +371,30 @@
int32_t lastAtomTag, int32_t uid, int32_t pid);
/**
- * Records that the pull of an atom has failed
+ * Records that the pull of an atom has failed. Eg, if the client indicated the pull failed, if
+ * the pull timed out, or if the outgoing binder call failed.
+ * This count will only increment if the puller was actually invoked.
+ *
+ * It does not include a pull not occurring due to not finding the appropriate
+ * puller. These cases are covered in other counts.
*/
void notePullFailed(int atomId);
/**
- * Records that the pull of StatsCompanionService atom has failed
+ * Records that the pull of an atom has failed due to not having a uid provider.
*/
- void noteStatsCompanionPullFailed(int atomId);
+ void notePullUidProviderNotFound(int atomId);
/**
- * Records that the pull of a StatsCompanionService atom has failed due to a failed binder
- * transaction. This can happen when StatsCompanionService returns too
- * much data (the max Binder parcel size is 1MB)
+ * Records that the pull of an atom has failed due not finding a puller registered by a
+ * trusted uid.
*/
- void noteStatsCompanionPullBinderTransactionFailed(int atomId);
+ void notePullerNotFound(int atomId);
+
+ /**
+ * Records that the pull has failed due to the outgoing binder call failing.
+ */
+ void notePullBinderCallFailed(int atomId);
/**
* A pull with no data occurred
@@ -503,12 +512,13 @@
long pullTimeout = 0;
long pullExceedMaxDelay = 0;
long pullFailed = 0;
- long statsCompanionPullFailed = 0;
- long statsCompanionPullBinderTransactionFailed = 0;
+ long pullUidProviderNotFound = 0;
+ long pullerNotFound = 0;
long emptyData = 0;
long registeredCount = 0;
long unregisteredCount = 0;
int32_t atomErrorCount = 0;
+ long binderCallFailCount = 0;
} PulledAtomStats;
typedef struct {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index c4bd054..cc4c565 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -326,13 +326,12 @@
return;
}
const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
if (pullDelayNs > mMaxPullDelayNs) {
ALOGE("Pull finish too late for atom %d", mPullTagId);
StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
- StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
return;
}
- StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
for (const auto& data : allData) {
LogEvent localCopy = data->makeCopy();
localCopy.setElapsedTimestampNs(timestampNs);
@@ -415,6 +414,13 @@
if (!pullSuccess || allData.size() == 0) {
return;
}
+ const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs;
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+ if (pullDelayNs > mMaxPullDelayNs) {
+ ALOGE("Pull finish too late for atom %d", mPullTagId);
+ StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
+ return;
+ }
for (const auto& data : allData) {
if (mEventMatcherWizard->matchLogEvent(
*data, mWhatMatcherIndex) == MatchingState::kMatched) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index f34423a..e5ec72e 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -584,11 +584,6 @@
return;
}
- if (allData.size() == 0) {
- VLOG("Data pulled is empty");
- StatsdStats::getInstance().noteEmptyData(mPullTagId);
- }
-
mMatchedMetricDimensionKeys.clear();
for (const auto& data : allData) {
LogEvent localCopy = data->makeCopy();
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index bed836a..7b68721 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -19,6 +19,7 @@
#include "ShellSubscriber.h"
#include <android-base/file.h>
+
#include "matchers/matcher_util.h"
#include "stats_log_util.h"
@@ -32,41 +33,52 @@
void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) {
int myToken = claimToken();
+ VLOG("ShellSubscriber: new subscription %d has come in", myToken);
mSubscriptionShouldEnd.notify_one();
shared_ptr<SubscriptionInfo> mySubscriptionInfo = make_shared<SubscriptionInfo>(in, out);
- if (!readConfig(mySubscriptionInfo)) {
- return;
- }
+ if (!readConfig(mySubscriptionInfo)) return;
- // critical-section
- std::unique_lock<std::mutex> lock(mMutex);
- if (myToken != mToken) {
- // Some other subscription has already come in. Stop.
- return;
- }
- mSubscriptionInfo = mySubscriptionInfo;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (myToken != mToken) {
+ // Some other subscription has already come in. Stop.
+ return;
+ }
+ mSubscriptionInfo = mySubscriptionInfo;
- if (mySubscriptionInfo->mPulledInfo.size() > 0 && mySubscriptionInfo->mPullIntervalMin > 0) {
- // This thread terminates after it detects that mToken has changed.
+ spawnHelperThreadsLocked(mySubscriptionInfo, myToken);
+ waitForSubscriptionToEndLocked(mySubscriptionInfo, myToken, lock, timeoutSec);
+
+ if (mSubscriptionInfo == mySubscriptionInfo) {
+ mSubscriptionInfo = nullptr;
+ }
+
+ }
+}
+
+void ShellSubscriber::spawnHelperThreadsLocked(shared_ptr<SubscriptionInfo> myInfo, int myToken) {
+ if (!myInfo->mPulledInfo.empty() && myInfo->mPullIntervalMin > 0) {
std::thread puller([this, myToken] { startPull(myToken); });
puller.detach();
}
- // Block until subscription has ended.
- if (timeoutSec > 0) {
- mSubscriptionShouldEnd.wait_for(
- lock, timeoutSec * 1s, [this, myToken, &mySubscriptionInfo] {
- return mToken != myToken || !mySubscriptionInfo->mClientAlive;
- });
- } else {
- mSubscriptionShouldEnd.wait(lock, [this, myToken, &mySubscriptionInfo] {
- return mToken != myToken || !mySubscriptionInfo->mClientAlive;
- });
- }
+ std::thread heartbeatSender([this, myToken] { sendHeartbeats(myToken); });
+ heartbeatSender.detach();
+}
- if (mSubscriptionInfo == mySubscriptionInfo) {
- mSubscriptionInfo = nullptr;
+void ShellSubscriber::waitForSubscriptionToEndLocked(shared_ptr<SubscriptionInfo> myInfo,
+ int myToken,
+ std::unique_lock<std::mutex>& lock,
+ int timeoutSec) {
+ if (timeoutSec > 0) {
+ mSubscriptionShouldEnd.wait_for(lock, timeoutSec * 1s, [this, myToken, &myInfo] {
+ return mToken != myToken || !myInfo->mClientAlive;
+ });
+ } else {
+ mSubscriptionShouldEnd.wait(lock, [this, myToken, &myInfo] {
+ return mToken != myToken || !myInfo->mClientAlive;
+ });
}
}
@@ -129,51 +141,55 @@
return true;
}
-void ShellSubscriber::startPull(int64_t myToken) {
+void ShellSubscriber::startPull(int myToken) {
+ VLOG("ShellSubscriber: pull thread %d starting", myToken);
while (true) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (!mSubscriptionInfo || mToken != myToken) {
- VLOG("Pulling thread %lld done!", (long long)myToken);
- return;
- }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mSubscriptionInfo || mToken != myToken) {
+ VLOG("ShellSubscriber: pulling thread %d done!", myToken);
+ return;
+ }
- int64_t nowMillis = getElapsedRealtimeMillis();
- for (auto& pullInfo : mSubscriptionInfo->mPulledInfo) {
- if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval < nowMillis) {
- vector<std::shared_ptr<LogEvent>> data;
+ int64_t nowMillis = getElapsedRealtimeMillis();
+ for (PullInfo& pullInfo : mSubscriptionInfo->mPulledInfo) {
+ if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval >= nowMillis) {
+ continue;
+ }
+
vector<int32_t> uids;
- uids.insert(uids.end(), pullInfo.mPullUids.begin(), pullInfo.mPullUids.end());
- // This is slow. Consider storing the uids per app and listening to uidmap updates.
- for (const string& pkg : pullInfo.mPullPackages) {
- set<int32_t> uidsForPkg = mUidMap->getAppUid(pkg);
- uids.insert(uids.end(), uidsForPkg.begin(), uidsForPkg.end());
- }
- uids.push_back(DEFAULT_PULL_UID);
- mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, &data);
- VLOG("pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
+ getUidsForPullAtom(&uids, pullInfo);
- if (!writePulledAtomsLocked(data, pullInfo.mPullerMatcher)) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
- return;
- }
+ vector<std::shared_ptr<LogEvent>> data;
+ mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, &data);
+ VLOG("Pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
+ writePulledAtomsLocked(data, pullInfo.mPullerMatcher);
+
pullInfo.mPrevPullElapsedRealtimeMs = nowMillis;
}
}
- VLOG("Pulling thread %lld sleep....", (long long)myToken);
+ VLOG("ShellSubscriber: pulling thread %d sleeping for %d ms", myToken,
+ mSubscriptionInfo->mPullIntervalMin);
std::this_thread::sleep_for(std::chrono::milliseconds(mSubscriptionInfo->mPullIntervalMin));
}
}
-// \return boolean indicating if writes were successful (will return false if
-// client dies)
-bool ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
+void ShellSubscriber::getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo) {
+ uids->insert(uids->end(), pullInfo.mPullUids.begin(), pullInfo.mPullUids.end());
+ // This is slow. Consider storing the uids per app and listening to uidmap updates.
+ for (const string& pkg : pullInfo.mPullPackages) {
+ set<int32_t> uidsForPkg = mUidMap->getAppUid(pkg);
+ uids->insert(uids->end(), uidsForPkg.begin(), uidsForPkg.end());
+ }
+ uids->push_back(DEFAULT_PULL_UID);
+}
+
+void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher) {
mProto.clear();
int count = 0;
for (const auto& event : data) {
- VLOG("%s", event->ToString().c_str());
if (matchesSimple(*mUidMap, matcher, *event)) {
count++;
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
@@ -183,55 +199,67 @@
}
}
- if (count > 0) {
- // First write the payload size.
- size_t bufferSize = mProto.size();
- if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &bufferSize,
- sizeof(bufferSize))) {
- return false;
- }
-
- VLOG("%d atoms, proto size: %zu", count, bufferSize);
- // Then write the payload.
- if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
- return false;
- }
- }
-
- return true;
+ if (count > 0) attemptWriteToSocketLocked(mProto.size());
}
void ShellSubscriber::onLogEvent(const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
- if (!mSubscriptionInfo) {
- return;
- }
+ if (!mSubscriptionInfo) return;
mProto.clear();
for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) {
if (matchesSimple(*mUidMap, matcher, event)) {
- VLOG("%s", event.ToString().c_str());
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event.ToProto(mProto);
mProto.end(atomToken);
+ attemptWriteToSocketLocked(mProto.size());
+ }
+ }
+}
- // First write the payload size.
- size_t bufferSize = mProto.size();
- if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &bufferSize,
- sizeof(bufferSize))) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
+// Tries to write the atom encoded in mProto to the socket. If the write fails
+// because the read end of the pipe has closed, signals to other threads that
+// the subscription should end.
+void ShellSubscriber::attemptWriteToSocketLocked(size_t dataSize) {
+ // First write the payload size.
+ if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &dataSize, sizeof(dataSize))) {
+ mSubscriptionInfo->mClientAlive = false;
+ mSubscriptionShouldEnd.notify_one();
+ return;
+ }
+
+ if (dataSize == 0) return;
+
+ // Then, write the payload.
+ if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
+ mSubscriptionInfo->mClientAlive = false;
+ mSubscriptionShouldEnd.notify_one();
+ return;
+ }
+
+ mLastWriteMs = getElapsedRealtimeMillis();
+}
+
+// Send a heartbeat, consisting solely of a data size of 0, if perfd has not
+// recently received any writes from statsd. When it receives the data size of
+// 0, perfd will not expect any data and recheck whether the shell command is
+// still running.
+void ShellSubscriber::sendHeartbeats(int myToken) {
+ while (true) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mSubscriptionInfo || myToken != mToken) {
+ VLOG("ShellSubscriber: heartbeat thread %d done!", myToken);
return;
}
- // Then write the payload.
- if (!mProto.flush(mSubscriptionInfo->mOutputFd)) {
- mSubscriptionInfo->mClientAlive = false;
- mSubscriptionShouldEnd.notify_one();
- return;
+ if (getElapsedRealtimeMillis() - mLastWriteMs > kMsBetweenHeartbeats) {
+ VLOG("ShellSubscriber: sending a heartbeat to perfd");
+ attemptWriteToSocketLocked(/*dataSize=*/0);
}
}
+ std::this_thread::sleep_for(std::chrono::milliseconds(kMsBetweenHeartbeats));
}
}
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 61457d8..26c8a2a 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -38,11 +38,11 @@
*
* A shell subscription lasts *until shell exits*. Unlike config based clients, a shell client
* communicates with statsd via file descriptors. They can subscribe pushed and pulled atoms.
- * The atoms are sent back to the client in real time, as opposed to
- * keeping the data in memory. Shell clients do not subscribe aggregated metrics, as they are
- * responsible for doing the aggregation after receiving the atom events.
+ * The atoms are sent back to the client in real time, as opposed to keeping the data in memory.
+ * Shell clients do not subscribe aggregated metrics, as they are responsible for doing the
+ * aggregation after receiving the atom events.
*
- * Shell client pass ShellSubscription in the proto binary format. Client can update the
+ * Shell clients pass ShellSubscription in the proto binary format. Clients can update the
* subscription by sending a new subscription. The new subscription would replace the old one.
* Input data stream format is:
*
@@ -54,7 +54,7 @@
* The stream would be in the following format:
* |size_t|shellData proto|size_t|shellData proto|....
*
- * Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
+ * Only one shell subscriber is allowed at a time because each shell subscriber blocks one thread
* until it exits.
*/
class ShellSubscriber : public virtual RefBase {
@@ -100,11 +100,28 @@
bool readConfig(std::shared_ptr<SubscriptionInfo> subscriptionInfo);
- void startPull(int64_t myToken);
+ void spawnHelperThreadsLocked(std::shared_ptr<SubscriptionInfo> myInfo, int myToken);
- bool writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
+ void waitForSubscriptionToEndLocked(std::shared_ptr<SubscriptionInfo> myInfo,
+ int myToken,
+ std::unique_lock<std::mutex>& lock,
+ int timeoutSec);
+
+ void startPull(int myToken);
+
+ void writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher);
+ void getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo);
+
+ void attemptWriteToSocketLocked(size_t dataSize);
+
+ // Send ocassional heartbeats for two reasons: (a) for statsd to detect when
+ // the read end of the pipe has closed and (b) for perfd to escape a
+ // blocking read call and recheck if the user has terminated the
+ // subscription.
+ void sendHeartbeats(int myToken);
+
sp<UidMap> mUidMap;
sp<StatsPullerManager> mPullerMgr;
@@ -120,6 +137,11 @@
int mToken = 0;
const int32_t DEFAULT_PULL_UID = AID_SYSTEM;
+
+ // Tracks when we last send data to perfd. We need that time to determine
+ // when next to send a heartbeat.
+ int64_t mLastWriteMs = 0;
+ const int64_t kMsBetweenHeartbeats = 1000;
};
} // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 868247b..1121392 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -456,12 +456,15 @@
optional int64 pull_timeout = 10;
optional int64 pull_exceed_max_delay = 11;
optional int64 pull_failed = 12;
- optional int64 stats_companion_pull_failed = 13;
- optional int64 stats_companion_pull_binder_transaction_failed = 14;
+ optional int64 stats_companion_pull_failed = 13 [deprecated = true];
+ optional int64 stats_companion_pull_binder_transaction_failed = 14 [deprecated = true];
optional int64 empty_data = 15;
optional int64 registered_count = 16;
optional int64 unregistered_count = 17;
optional int32 atom_error_count = 18;
+ optional int64 binder_call_failed = 19;
+ optional int64 failed_uid_provider_not_found = 20;
+ optional int64 puller_not_found = 21;
}
repeated PulledAtomStats pulled_atom_stats = 10;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 2acffee..bafdfcb 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -74,12 +74,13 @@
const int FIELD_ID_PULL_TIMEOUT = 10;
const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
const int FIELD_ID_PULL_FAILED = 12;
-const int FIELD_ID_STATS_COMPANION_FAILED = 13;
-const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
const int FIELD_ID_EMPTY_DATA = 15;
const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
const int FIELD_ID_ATOM_ERROR_COUNT = 18;
+const int FIELD_ID_BINDER_CALL_FAIL_COUNT = 19;
+const int FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND = 20;
+const int FIELD_ID_PULLER_NOT_FOUND = 21;
// for AtomMetricStats proto
const int FIELD_ID_ATOM_METRIC_STATS = 17;
@@ -483,10 +484,6 @@
(long long)pair.second.pullExceedMaxDelay);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED,
(long long)pair.second.pullFailed);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_FAILED,
- (long long)pair.second.statsCompanionPullFailed);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED,
- (long long)pair.second.statsCompanionPullBinderTransactionFailed);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
(long long)pair.second.emptyData);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
@@ -494,6 +491,12 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
(long long) pair.second.unregisteredCount);
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_ERROR_COUNT, pair.second.atomErrorCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BINDER_CALL_FAIL_COUNT,
+ (long long)pair.second.binderCallFailCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND,
+ (long long)pair.second.pullUidProviderNotFound);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULLER_NOT_FOUND,
+ (long long)pair.second.pullerNotFound);
protoOutput->end(token);
}
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index cdde603..948d587 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -302,7 +302,10 @@
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
-
+ stats.notePullBinderCallFailed(util::DISK_SPACE);
+ stats.notePullUidProviderNotFound(util::DISK_SPACE);
+ stats.notePullerNotFound(util::DISK_SPACE);
+ stats.notePullerNotFound(util::DISK_SPACE);
vector<uint8_t> output;
stats.dumpStats(&output, false);
@@ -322,6 +325,9 @@
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
+ EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
}
TEST(StatsdStatsTest, TestAtomMetricsStats) {
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index 7b952d7..363fcb4 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -86,28 +86,34 @@
// wait for the data to be written.
std::this_thread::sleep_for(100ms);
- int expected_data_size = expectedData.ByteSize();
+ // Because we might receive heartbeats from statsd, consisting of data sizes
+ // of 0, encapsulate reads within a while loop.
+ bool readAtom = false;
+ while (!readAtom) {
+ // Read the atom size.
+ size_t dataSize = 0;
+ read(fds_data[0], &dataSize, sizeof(dataSize));
+ if (dataSize == 0) continue;
+ EXPECT_EQ(expectedData.ByteSize(), int(dataSize));
- // now read from the pipe. firstly read the atom size.
- size_t dataSize = 0;
- EXPECT_EQ((int)sizeof(dataSize), read(fds_data[0], &dataSize, sizeof(dataSize)));
+ // Read that much data in proto binary format.
+ vector<uint8_t> dataBuffer(dataSize);
+ EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
- EXPECT_EQ(expected_data_size, (int)dataSize);
+ // Make sure the received bytes can be parsed to an atom.
+ ShellData receivedAtom;
+ EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
- // then read that much data which is the atom in proto binary format
- vector<uint8_t> dataBuffer(dataSize);
- EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
+ // Serialize the expected atom to byte array and compare to make sure
+ // they are the same.
+ vector<uint8_t> expectedAtomBuffer(expectedData.ByteSize());
+ expectedData.SerializeToArray(expectedAtomBuffer.data(), expectedData.ByteSize());
+ EXPECT_EQ(expectedAtomBuffer, dataBuffer);
- // make sure the received bytes can be parsed to an atom
- ShellData receivedAtom;
- EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
+ readAtom = true;
+ }
- // serialze the expected atom to bytes. and compare. to make sure they are the same.
- vector<uint8_t> atomBuffer(expected_data_size);
- expectedData.SerializeToArray(&atomBuffer[0], expected_data_size);
- EXPECT_EQ(atomBuffer, dataBuffer);
close(fds_data[0]);
-
if (reader.joinable()) {
reader.join();
}
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index a97f132..6384fb1 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -208,7 +208,6 @@
ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
for (StatsLogReport statsLog : report.getMetricsList()) {
if (isTrackedMetric(statsLog.getMetricId())) {
- LOGGER.info(statsLog.toString());
dumper.dump(statsLog);
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 77b3c81..ed0ea55 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -513,6 +513,13 @@
*/
public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12;
+ /**
+ * Action to trigger the Accessibility Shortcut. This shortcut has a hardware trigger and can
+ * be activated by holding down the two volume keys.
+ * @hide
+ */
+ public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e0ae750..bfae632 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2748,11 +2748,7 @@
* @return True if the activity is in multi-window mode.
*/
public boolean isInMultiWindowMode() {
- try {
- return ActivityTaskManager.getService().isInMultiWindowMode(mToken);
- } catch (RemoteException e) {
- }
- return false;
+ return mLastDispatchedIsInMultiWindowMode == Boolean.TRUE;
}
/**
@@ -2795,11 +2791,7 @@
* @return True if the activity is in picture-in-picture mode.
*/
public boolean isInPictureInPictureMode() {
- try {
- return ActivityTaskManager.getService().isInPictureInPictureMode(mToken);
- } catch (RemoteException e) {
- }
- return false;
+ return mLastDispatchedIsInPictureInPictureMode == Boolean.TRUE;
}
/**
@@ -3751,7 +3743,6 @@
* To receive this callback, you must return true from onKeyDown for the current
* event stream.
*
- * @see KeyEvent.Callback#onKeyLongPress()
* @see KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
*/
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d1b6efd..9067069 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1719,31 +1719,50 @@
configuration.windowConfiguration.getActivityType());
pw.println(); pw.print(" ");
- pw.print(" id=" + persistentId);
- pw.print(" stackId=" + stackId);
- pw.print(" userId=" + userId);
- pw.print(" hasTask=" + (id != -1));
- pw.print(" lastActiveTime=" + lastActiveTime);
- pw.println(); pw.print(" ");
- pw.print(" baseIntent=" + baseIntent);
- pw.println(); pw.print(" ");
- pw.print(" isExcluded="
- + ((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
- pw.print(" activityType=" + activityType);
- pw.print(" windowingMode=" + windowingMode);
- pw.print(" supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow);
+ pw.print(" id="); pw.print(persistentId);
+ pw.print(" stackId="); pw.print(stackId);
+ pw.print(" userId="); pw.print(userId);
+ pw.print(" hasTask="); pw.print((id != -1));
+ pw.print(" lastActiveTime="); pw.println(lastActiveTime);
+ pw.print(" "); pw.print(" baseIntent="); pw.println(baseIntent);
+ if (baseActivity != null) {
+ pw.print(" "); pw.print(" baseActivity=");
+ pw.println(baseActivity.toShortString());
+ }
+ if (topActivity != null) {
+ pw.print(" "); pw.print(" topActivity="); pw.println(topActivity.toShortString());
+ }
+ if (origActivity != null) {
+ pw.print(" "); pw.print(" origActivity=");
+ pw.println(origActivity.toShortString());
+ }
+ if (realActivity != null) {
+ pw.print(" "); pw.print(" realActivity=");
+ pw.println(realActivity.toShortString());
+ }
+ pw.print(" ");
+ pw.print(" isExcluded=");
+ pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
+ pw.print(" activityType="); pw.print(activityType);
+ pw.print(" windowingMode="); pw.print(windowingMode);
+ pw.print(" supportsSplitScreenMultiWindow=");
+ pw.println(supportsSplitScreenMultiWindow);
if (taskDescription != null) {
- pw.println(); pw.print(" ");
+ pw.print(" ");
final ActivityManager.TaskDescription td = taskDescription;
pw.print(" taskDescription {");
- pw.print(" colorBackground=#" + Integer.toHexString(td.getBackgroundColor()));
- pw.print(" colorPrimary=#" + Integer.toHexString(td.getPrimaryColor()));
- pw.print(" iconRes=" + td.getIconResourcePackage() + "/" + td.getIconResource());
- pw.print(" iconBitmap=" + (td.getIconFilename() != null
- || td.getInMemoryIcon() != null));
- pw.print(" resizeMode=" + ActivityInfo.resizeModeToString(td.getResizeMode()));
- pw.print(" minWidth=" + td.getMinWidth());
- pw.print(" minHeight=" + td.getMinHeight());
+ pw.print(" colorBackground=#");
+ pw.print(Integer.toHexString(td.getBackgroundColor()));
+ pw.print(" colorPrimary=#");
+ pw.print(Integer.toHexString(td.getPrimaryColor()));
+ pw.print(" iconRes=");
+ pw.print(td.getIconResourcePackage() + "/" + td.getIconResource());
+ pw.print(" iconBitmap=");
+ pw.print(td.getIconFilename() != null || td.getInMemoryIcon() != null);
+ pw.print(" resizeMode=");
+ pw.print(ActivityInfo.resizeModeToString(td.getResizeMode()));
+ pw.print(" minWidth="); pw.print(td.getMinWidth());
+ pw.print(" minHeight="); pw.print(td.getMinHeight());
pw.println(" }");
}
}
@@ -2431,8 +2450,7 @@
* has access to it.
*
* @see ActivityOptions#setLaunchDisplayId(int)
- * @see android.view.Display.FLAG_PRIVATE
- * @see android.view.Display.TYPE_VIRTUAL
+ * @see android.view.Display#FLAG_PRIVATE
*
* @param context Source context, from which an activity will be started.
* @param displayId Target display id.
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0129aab..80d2e6c 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -266,6 +266,14 @@
"android:activity.disallowEnterPictureInPictureWhileLaunching";
/**
+ * Indicates flags should be applied to the launching activity such that it will behave
+ * correctly in a bubble.
+ * @hide
+ */
+ private static final String KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES =
+ "android:activity.applyActivityFlagsForBubbles";
+
+ /**
* For Activity transitions, the calling Activity's TransitionListener used to
* notify the called Activity when the shared element and the exit transitions
* complete.
@@ -354,6 +362,7 @@
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
+ private boolean mApplyActivityFlagsForBubbles;
private boolean mTaskAlwaysOnTop;
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
@@ -1033,6 +1042,8 @@
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, false);
+ mApplyActivityFlagsForBubbles = opts.getBoolean(
+ KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES, false);
if (opts.containsKey(KEY_ANIM_SPECS)) {
Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
@@ -1465,6 +1476,16 @@
return mDisallowEnterPictureInPictureWhileLaunching;
}
+ /** @hide */
+ public void setApplyActivityFlagsForBubbles(boolean apply) {
+ mApplyActivityFlagsForBubbles = apply;
+ }
+
+ /** @hide */
+ public boolean isApplyActivityFlagsForBubbles() {
+ return mApplyActivityFlagsForBubbles;
+ }
+
/**
* Update the current values in this ActivityOptions from those supplied
* in <var>otherOptions</var>. Any values
@@ -1663,6 +1684,9 @@
b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
mDisallowEnterPictureInPictureWhileLaunching);
}
+ if (mApplyActivityFlagsForBubbles) {
+ b.putBoolean(KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES, mApplyActivityFlagsForBubbles);
+ }
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e19d5ec..e97ebd7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -17,6 +17,8 @@
package android.app;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
@@ -407,6 +409,9 @@
@GuardedBy("this")
private @Nullable Map<SafeCancellationTransport, CancellationSignal> mRemoteCancellations;
+ private final Map<IBinder, Integer> mLastReportedWindowingMode = Collections.synchronizedMap(
+ new ArrayMap<>());
+
private static final class ProviderKey {
final String authority;
final int userId;
@@ -3329,6 +3334,8 @@
" did not call through to super.onCreate()");
}
r.activity = activity;
+ mLastReportedWindowingMode.put(activity.getActivityToken(),
+ config.windowConfiguration.getWindowingMode());
}
r.setState(ON_CREATE);
@@ -3752,32 +3759,6 @@
}
@Override
- public void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
- Configuration overrideConfig) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r != null) {
- final Configuration newConfig = new Configuration(mConfiguration);
- if (overrideConfig != null) {
- newConfig.updateFrom(overrideConfig);
- }
- r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
- }
- }
-
- @Override
- public void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
- Configuration overrideConfig) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r != null) {
- final Configuration newConfig = new Configuration(mConfiguration);
- if (overrideConfig != null) {
- newConfig.updateFrom(overrideConfig);
- }
- r.activity.dispatchPictureInPictureModeChanged(isInPipMode, newConfig);
- }
- }
-
- @Override
public void handlePictureInPictureRequested(IBinder token) {
final ActivityClientRecord r = mActivities.get(token);
if (r == null) {
@@ -5274,8 +5255,15 @@
throw e.rethrowFromSystemServer();
}
+ // Save the current windowing mode to be restored and compared to the new configuration's
+ // windowing mode (needed because we update the last reported windowing mode when launching
+ // an activity and we can't tell inside performLaunchActivity whether we are relaunching)
+ final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault(
+ r.activity.getActivityToken(), WINDOWING_MODE_UNDEFINED);
handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
+ mLastReportedWindowingMode.put(r.activity.getActivityToken(), oldWindowingMode);
+ handleWindowingModeChangeIfNeeded(r.activity, r.activity.mCurrentConfig);
if (pendingActions != null) {
// Only report a successful relaunch to WindowManager.
@@ -5558,6 +5546,10 @@
throw new IllegalArgumentException("Activity token not set. Is the activity attached?");
}
+ // multi-window / pip mode changes, if any, should be sent before the configuration change
+ // callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
+ handleWindowingModeChangeIfNeeded(activity, newConfig);
+
boolean shouldChangeConfig = false;
if (activity.mCurrentConfig == null) {
shouldChangeConfig = true;
@@ -5752,6 +5744,35 @@
}
/**
+ * Sends windowing mode change callbacks to {@link Activity} if applicable.
+ *
+ * See also {@link Activity#onMultiWindowModeChanged(boolean, Configuration)} and
+ * {@link Activity#onPictureInPictureModeChanged(boolean, Configuration)}
+ */
+ private void handleWindowingModeChangeIfNeeded(Activity activity,
+ Configuration newConfiguration) {
+ final int newWindowingMode = newConfiguration.windowConfiguration.getWindowingMode();
+ final IBinder token = activity.getActivityToken();
+ final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault(token,
+ WINDOWING_MODE_UNDEFINED);
+ if (oldWindowingMode == newWindowingMode) return;
+ // PiP callback is sent before the MW one.
+ if (newWindowingMode == WINDOWING_MODE_PINNED) {
+ activity.dispatchPictureInPictureModeChanged(true, newConfiguration);
+ } else if (oldWindowingMode == WINDOWING_MODE_PINNED) {
+ activity.dispatchPictureInPictureModeChanged(false, newConfiguration);
+ }
+ final boolean wasInMultiWindowMode = WindowConfiguration.inMultiWindowMode(
+ oldWindowingMode);
+ final boolean nowInMultiWindowMode = WindowConfiguration.inMultiWindowMode(
+ newWindowingMode);
+ if (wasInMultiWindowMode != nowInMultiWindowMode) {
+ activity.dispatchMultiWindowModeChanged(nowInMultiWindowMode, newConfiguration);
+ }
+ mLastReportedWindowingMode.put(token, newWindowingMode);
+ }
+
+ /**
* Updates the application info.
*
* This only works in the system process. Must be called on the main thread.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 1098fa1..635ed13 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -29,6 +29,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.AttributeSet;
@@ -444,6 +445,14 @@
}
/**
+ * @hide
+ * @return virtual display.
+ */
+ public VirtualDisplay getVirtualDisplay() {
+ return mTaskEmbedder.getVirtualDisplay();
+ }
+
+ /**
* Injects a pair of down/up key events with keycode {@link KeyEvent#KEYCODE_BACK} to the
* virtual display.
*/
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 33bacf0..d321288 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -66,6 +66,7 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsNotedCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IAppOpsStartedCallback;
import com.android.internal.app.MessageSamplingConfig;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.ZygoteInit;
@@ -201,6 +202,10 @@
private final ArrayMap<OnOpActiveChangedListener, IAppOpsActiveCallback> mActiveWatchers =
new ArrayMap<>();
+ @GuardedBy("mStartedWatchers")
+ private final ArrayMap<OnOpStartedListener, IAppOpsStartedCallback> mStartedWatchers =
+ new ArrayMap<>();
+
@GuardedBy("mNotedWatchers")
private final ArrayMap<OnOpNotedListener, IAppOpsNotedCallback> mNotedWatchers =
new ArrayMap<>();
@@ -6367,6 +6372,25 @@
default void onOpActiveChanged(int op, int uid, String packageName, boolean active) { }
}
+ /**
+ * Callback for notification of an op being started.
+ *
+ * @hide
+ */
+ public interface OnOpStartedListener {
+ /**
+ * Called when an op was started.
+ *
+ * Note: This is only for op starts. It is not called when an op is noted or stopped.
+ *
+ * @param op The op code.
+ * @param uid The UID performing the operation.
+ * @param packageName The package performing the operation.
+ * @param result The result of the start.
+ */
+ void onOpStarted(int op, int uid, String packageName, int result);
+ }
+
AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
@@ -6858,10 +6882,7 @@
* @param ops The operations to watch.
* @param callback Where to report changes.
*
- * @see #isOperationActive
* @see #stopWatchingActive
- * @see #startOp(int, int, String, boolean, String, String)
- * @see #finishOp(int, int, String, String)
*/
// TODO: Uncomment below annotation once b/73559440 is fixed
// @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
@@ -6909,10 +6930,7 @@
* long running and it has a clear start and stop delimiters. Unregistering a
* non-registered callback has no effect.
*
- * @see #isOperationActive
* @see #startWatchingActive
- * @see #startOp(int, int, String, boolean, String, String)
- * @see #finishOp(int, int, String, String)
*/
public void stopWatchingActive(@NonNull OnOpActiveChangedListener callback) {
synchronized (mActiveWatchers) {
@@ -6928,6 +6946,73 @@
}
/**
+ * Start watching for started app-ops.
+ * An app-op may be long running and it has a clear start delimiter.
+ * If an op start is attempted by any package, you will get a callback.
+ * To change the watched ops for a registered callback you need to unregister and register it
+ * again.
+ *
+ * <p> If you don't hold the {@code android.Manifest.permission#WATCH_APPOPS} permission
+ * you can watch changes only for your UID.
+ *
+ * @param ops The operations to watch.
+ * @param callback Where to report changes.
+ *
+ * @see #stopWatchingStarted(OnOpStartedListener)
+ * @see #startWatchingActive(int[], OnOpActiveChangedListener)
+ * @see #startWatchingNoted(int[], OnOpNotedListener)
+ * @see #startOp(int, int, String, boolean, String, String)
+ * @see #finishOp(int, int, String, String)
+ *
+ * @hide
+ */
+ @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
+ public void startWatchingStarted(@NonNull int[] ops, @NonNull OnOpStartedListener callback) {
+ IAppOpsStartedCallback cb;
+ synchronized (mStartedWatchers) {
+ if (mStartedWatchers.containsKey(callback)) {
+ return;
+ }
+ cb = new IAppOpsStartedCallback.Stub() {
+ @Override
+ public void opStarted(int op, int uid, String packageName, int mode) {
+ callback.onOpStarted(op, uid, packageName, mode);
+ }
+ };
+ mStartedWatchers.put(callback, cb);
+ }
+ try {
+ mService.startWatchingStarted(ops, cb);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stop watching for started app-ops.
+ * An app-op may be long running and it has a clear start delimiter.
+ * Henceforth, if an op start is attempted by any package, you will not get a callback.
+ * Unregistering a non-registered callback has no effect.
+ *
+ * @see #startWatchingStarted(int[], OnOpStartedListener)
+ * @see #startOp(int, int, String, boolean, String, String)
+ *
+ * @hide
+ */
+ public void stopWatchingStarted(@NonNull OnOpStartedListener callback) {
+ synchronized (mStartedWatchers) {
+ final IAppOpsStartedCallback cb = mStartedWatchers.remove(callback);
+ if (cb != null) {
+ try {
+ mService.stopWatchingStarted(cb);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ /**
* Start watching for noted app ops. An app op may be immediate or long running.
* Immediate ops are noted while long running ones are started and stopped. This
* method allows registering a listener to be notified when an app op is noted. If
@@ -6941,6 +7026,7 @@
* @param callback Where to report changes.
*
* @see #startWatchingActive(int[], OnOpActiveChangedListener)
+ * @see #startWatchingStarted(int[], OnOpStartedListener)
* @see #stopWatchingNoted(OnOpNotedListener)
* @see #noteOp(String, int, String, String, String)
*
@@ -6980,7 +7066,7 @@
*/
public void stopWatchingNoted(@NonNull OnOpNotedListener callback) {
synchronized (mNotedWatchers) {
- final IAppOpsNotedCallback cb = mNotedWatchers.get(callback);
+ final IAppOpsNotedCallback cb = mNotedWatchers.remove(callback);
if (cb != null) {
try {
mService.stopWatchingNoted(cb);
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index d2235f1..83465b0 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -146,17 +146,9 @@
/** Deliver result from another activity. */
public abstract void handleSendResult(IBinder token, List<ResultInfo> results, String reason);
- /** Deliver multi-window mode change notification. */
- public abstract void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
- Configuration overrideConfig);
-
/** Deliver new intent. */
public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents);
- /** Deliver picture-in-picture mode change notification. */
- public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
- Configuration overrideConfig);
-
/** Request that an activity enter picture-in-picture. */
public abstract void handlePictureInPictureRequested(IBinder token);
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index fe13b8f..f236813 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -58,7 +58,7 @@
@RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
public void startDream(@NonNull ComponentName name) {
try {
- mService.testDream(mContext.getUserId(), name);
+ mService.dream();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -99,4 +99,22 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns whether the device is Dreaming.
+ *
+ * <p> This is only used for testing the dream service APIs.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE)
+ public boolean isDreaming() {
+ try {
+ return mService.isDreaming();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 833bfed..e84c5e5 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -99,7 +99,6 @@
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
int getUidProcessState(int uid, in String callingPackage);
- boolean isUidActiveOrForeground(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -673,4 +672,9 @@
* @param state The customized state data
*/
void setProcessStateSummary(in byte[] state);
+
+ /**
+ * Return whether the app freezer is supported (true) or not (false) by this system.
+ */
+ boolean isAppFreezerSupported();
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index b7ceb6a..3ce7689 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -300,8 +300,6 @@
void suppressResizeConfigChanges(boolean suppress);
boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds);
- boolean isInMultiWindowMode(in IBinder token);
- boolean isInPictureInPictureMode(in IBinder token);
boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
void requestPictureInPictureMode(in IBinder token);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 1a619bd..2d06ee8 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -205,4 +205,15 @@
* @param {@code true} if the task got focus, {@code false} if it lost it.
*/
void onTaskFocusChanged(int taskId, boolean focused);
+
+ /**
+ * Called when a task changes its requested orientation. It is different from {@link
+ * #onActivityRequestedOrientationChanged(int, int)} in the sense that this method is called
+ * when a task changes requested orientation due to activity launch, dimiss or reparenting.
+ *
+ * @param taskId id of the task.
+ * @param requestedOrientation the new requested orientation of this task as screen orientations
+ * in {@link android.content.pm.ActivityInfo}.
+ */
+ void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 818a121..e233ade 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -732,7 +732,7 @@
* a non-null value if the intent needs to be intercepted.
*
* <p> Whenever a new activity is started, this method will be called on instances created
- * using {@link #Instrumentation.ActivityMonitor()} to check if there is a match. In case
+ * using {@link #ActivityMonitor()} to check if there is a match. In case
* of a match, the activity start will be blocked and the returned result will be used.
*
* @param intent The intent used for starting the activity.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f26b136..a033b82 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3513,7 +3513,7 @@
}
/**
- * @deprecated use {@link Notification.Builder#Notification.Builder(Context, String)}
+ * @deprecated use {@link #Builder(Context, String)}
* instead. All posted Notifications must specify a NotificationChannel Id.
*/
@Deprecated
@@ -3631,7 +3631,7 @@
* @param shortcutId the {@link ShortcutInfo#getId() id} of the shortcut this notification
* is linked to
*
- * @see Notification.BubbleMetadata.Builder#Builder(String)
+ * @see BubbleMetadata.Builder#Builder(String)
*/
@NonNull
public Builder setShortcutId(String shortcutId) {
@@ -5993,7 +5993,7 @@
* metadata matches the shortcutId set on the notification builder, if one was set.
* If the shortcutId's were specified but do not match, an exception is thrown here.
*
- * @see Notification.BubbleMetadata.Builder#Builder(String)
+ * @see BubbleMetadata.Builder#Builder(String)
* @see #setShortcutId(String)
*/
@NonNull
@@ -7297,7 +7297,7 @@
* Should be unique amongst all individuals in the conversation, and should be
* consistent during re-posts of the notification.
*
- * @see Message#Notification.MessagingStyle.Message(CharSequence, long, CharSequence)
+ * @see Message#Message(CharSequence, long, CharSequence)
*
* @return this object for method chaining
*
@@ -7317,7 +7317,7 @@
* Should be <code>null</code> for messages by the current user, in which case
* the platform will insert the user set in {@code MessagingStyle(Person)}.
*
- * @see Message#Notification.MessagingStyle.Message(CharSequence, long, CharSequence)
+ * @see Message#Message(CharSequence, long, CharSequence)
*
* @return this object for method chaining
*/
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index d6df400..eef9c02 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -368,7 +368,7 @@
* </p>
* </p>
*
- * @see {@link #addAutomaticZenRule(AutomaticZenRule)}
+ * @see #addAutomaticZenRule(AutomaticZenRule)
*/
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_AUTOMATIC_ZEN_RULE =
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index 1b13772..5a4244f 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -161,4 +161,4 @@
return new RemoteAction[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 47ccc2f..106f8ac 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1109,10 +1109,16 @@
Slog.v(TAG, "Changing resources "
+ resourcesImpl + " config to: " + config);
}
- int displayId = key.mDisplayId;
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+
tmpConfig.setTo(config);
+ // Apply the override configuration before setting the display adjustments to ensure that
+ // the process config does not override activity display adjustments.
+ final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(key.mOverrideConfiguration);
+ }
+
// Get new DisplayMetrics based on the DisplayAdjustments given to the ResourcesImpl. Update
// a copy if the CompatibilityInfo changed, because the ResourcesImpl object will handle the
// update internally.
@@ -1121,17 +1127,23 @@
daj = new DisplayAdjustments(daj);
daj.setCompatibilityInfo(compat);
}
+
+ final int displayId = key.mDisplayId;
if (displayId == Display.DEFAULT_DISPLAY) {
- daj.setConfiguration(config);
+ daj.setConfiguration(tmpConfig);
}
DisplayMetrics dm = getDisplayMetrics(displayId, daj);
if (displayId != Display.DEFAULT_DISPLAY) {
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+
+ // Re-apply the override configuration to ensure that configuration contexts based on
+ // a display context (ex: createDisplayContext().createConfigurationContext()) have the
+ // correct override.
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(key.mOverrideConfiguration);
+ }
}
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
resourcesImpl.updateConfiguration(tmpConfig, dm, compat);
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index bfa91aa..5d8daf8 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -195,4 +195,8 @@
@Override
public void onTaskFocusChanged(int taskId, boolean focused) {
}
+
+ @Override
+ public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ }
}
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 37e07de..a486b95 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -727,6 +727,16 @@
}
/**
+ * Returns {@code true} if the windowingMode represents a window in multi-window mode.
+ * I.e. sharing the screen with another activity.
+ * @hide
+ */
+ public static boolean inMultiWindowMode(int windowingMode) {
+ return windowingMode != WINDOWING_MODE_FULLSCREEN
+ && windowingMode != WINDOWING_MODE_UNDEFINED;
+ }
+
+ /**
* Returns true if the windowingMode represents a split window.
* @hide
*/
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index beb4449..3bc043e 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -805,7 +805,7 @@
* has a work profile that was restored from another work profile with serial number
* {@code ancestralSerialNumber}.
*
- * @see UserManager#getSerialNumberForUser(UserHandle)
+ * @see android.os.UserManager#getSerialNumberForUser(UserHandle)
*/
@Nullable
public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 917eeb8..253c73796 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -103,8 +103,6 @@
/**
* The name of the emergency role
- *
- * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
*/
public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
diff --git a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
deleted file mode 100644
index b150717..0000000
--- a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 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.app.servertransaction;
-
-import android.app.ClientTransactionHandler;
-import android.content.res.Configuration;
-import android.os.IBinder;
-import android.os.Parcel;
-
-import java.util.Objects;
-
-/**
- * Multi-window mode change message.
- * @hide
- */
-// TODO(lifecycler): Remove the use of this and just use the configuration change message to
-// communicate multi-window mode change with WindowConfiguration.
-public class MultiWindowModeChangeItem extends ClientTransactionItem {
-
- private boolean mIsInMultiWindowMode;
- private Configuration mOverrideConfig;
-
- @Override
- public void execute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- client.handleMultiWindowModeChanged(token, mIsInMultiWindowMode, mOverrideConfig);
- }
-
-
- // ObjectPoolItem implementation
-
- private MultiWindowModeChangeItem() {}
-
- /** Obtain an instance initialized with provided params. */
- public static MultiWindowModeChangeItem obtain(boolean isInMultiWindowMode,
- Configuration overrideConfig) {
- MultiWindowModeChangeItem instance = ObjectPool.obtain(MultiWindowModeChangeItem.class);
- if (instance == null) {
- instance = new MultiWindowModeChangeItem();
- }
- instance.mIsInMultiWindowMode = isInMultiWindowMode;
- instance.mOverrideConfig = overrideConfig;
-
- return instance;
- }
-
- @Override
- public void recycle() {
- mIsInMultiWindowMode = false;
- mOverrideConfig = null;
- ObjectPool.recycle(this);
- }
-
-
- // Parcelable implementation
-
- /** Write to Parcel. */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeBoolean(mIsInMultiWindowMode);
- dest.writeTypedObject(mOverrideConfig, flags);
- }
-
- /** Read from Parcel. */
- private MultiWindowModeChangeItem(Parcel in) {
- mIsInMultiWindowMode = in.readBoolean();
- mOverrideConfig = in.readTypedObject(Configuration.CREATOR);
- }
-
- public static final @android.annotation.NonNull Creator<MultiWindowModeChangeItem> CREATOR =
- new Creator<MultiWindowModeChangeItem>() {
- public MultiWindowModeChangeItem createFromParcel(Parcel in) {
- return new MultiWindowModeChangeItem(in);
- }
-
- public MultiWindowModeChangeItem[] newArray(int size) {
- return new MultiWindowModeChangeItem[size];
- }
- };
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- final MultiWindowModeChangeItem other = (MultiWindowModeChangeItem) o;
- return mIsInMultiWindowMode == other.mIsInMultiWindowMode
- && Objects.equals(mOverrideConfig, other.mOverrideConfig);
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + (mIsInMultiWindowMode ? 1 : 0);
- result = 31 * result + mOverrideConfig.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "MultiWindowModeChangeItem{isInMultiWindowMode=" + mIsInMultiWindowMode
- + ",overrideConfig=" + mOverrideConfig + "}";
- }
-}
diff --git a/core/java/android/app/servertransaction/PipModeChangeItem.java b/core/java/android/app/servertransaction/PipModeChangeItem.java
deleted file mode 100644
index 1955897..0000000
--- a/core/java/android/app/servertransaction/PipModeChangeItem.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 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.app.servertransaction;
-
-import android.app.ClientTransactionHandler;
-import android.content.res.Configuration;
-import android.os.IBinder;
-import android.os.Parcel;
-
-import java.util.Objects;
-
-/**
- * Picture in picture mode change message.
- * @hide
- */
-// TODO(lifecycler): Remove the use of this and just use the configuration change message to
-// communicate multi-window mode change with WindowConfiguration.
-public class PipModeChangeItem extends ClientTransactionItem {
-
- private boolean mIsInPipMode;
- private Configuration mOverrideConfig;
-
- @Override
- public void execute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- client.handlePictureInPictureModeChanged(token, mIsInPipMode, mOverrideConfig);
- }
-
-
- // ObjectPoolItem implementation
-
- private PipModeChangeItem() {}
-
- /** Obtain an instance initialized with provided params. */
- public static PipModeChangeItem obtain(boolean isInPipMode, Configuration overrideConfig) {
- PipModeChangeItem instance = ObjectPool.obtain(PipModeChangeItem.class);
- if (instance == null) {
- instance = new PipModeChangeItem();
- }
- instance.mIsInPipMode = isInPipMode;
- instance.mOverrideConfig = overrideConfig;
-
- return instance;
- }
-
- @Override
- public void recycle() {
- mIsInPipMode = false;
- mOverrideConfig = null;
- ObjectPool.recycle(this);
- }
-
-
- // Parcelable implementation
-
- /** Write to Parcel. */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeBoolean(mIsInPipMode);
- dest.writeTypedObject(mOverrideConfig, flags);
- }
-
- /** Read from Parcel. */
- private PipModeChangeItem(Parcel in) {
- mIsInPipMode = in.readBoolean();
- mOverrideConfig = in.readTypedObject(Configuration.CREATOR);
- }
-
- public static final @android.annotation.NonNull Creator<PipModeChangeItem> CREATOR =
- new Creator<PipModeChangeItem>() {
- public PipModeChangeItem createFromParcel(Parcel in) {
- return new PipModeChangeItem(in);
- }
-
- public PipModeChangeItem[] newArray(int size) {
- return new PipModeChangeItem[size];
- }
- };
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- final PipModeChangeItem other = (PipModeChangeItem) o;
- return mIsInPipMode == other.mIsInPipMode
- && Objects.equals(mOverrideConfig, other.mOverrideConfig);
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + (mIsInPipMode ? 1 : 0);
- result = 31 * result + mOverrideConfig.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "PipModeChangeItem{isInPipMode=" + mIsInPipMode
- + ",overrideConfig=" + mOverrideConfig + "}";
- }
-}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a4627d..c409613 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1449,7 +1449,7 @@
* on these schemes.
*
* @param uri The desired URI.
- * @return InputStream
+ * @return InputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
@@ -1484,6 +1484,9 @@
/**
* Synonym for {@link #openOutputStream(Uri, String)
* openOutputStream(uri, "w")}.
+ *
+ * @param uri The desired URI.
+ * @return an OutputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
*/
public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
@@ -1506,7 +1509,7 @@
*
* @param uri The desired URI.
* @param mode May be "w", "wa", "rw", or "rwt".
- * @return OutputStream
+ * @return an OutputStream or {@code null} if the provider recently crashed.
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
@@ -1563,8 +1566,9 @@
* @param uri The desired URI to open.
* @param mode The file mode to use, as per {@link ContentProvider#openFile
* ContentProvider.openFile}.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException if no
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
@@ -1608,8 +1612,9 @@
* @param cancellationSignal A signal to cancel the operation in progress,
* or null if none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException if no
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
@@ -1698,8 +1703,9 @@
* @param uri The desired URI to open.
* @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
* ContentProvider.openAssetFile}.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
@@ -1754,8 +1760,9 @@
* @param cancellationSignal A signal to cancel the operation in progress, or null if
* none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
- * @return Returns a new ParcelFileDescriptor pointing to the file. You
- * own this descriptor and are responsible for closing it when done.
+ * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the
+ * provider recently crashed. You own this descriptor and are responsible for closing it
+ * when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
@@ -1902,9 +1909,9 @@
* it is returning.
* @param opts Additional provider-dependent options.
* @return Returns a new ParcelFileDescriptor from which you can read the
- * data stream from the provider. Note that this may be a pipe, meaning
- * you can't seek in it. The only seek you should do is if the
- * AssetFileDescriptor contains an offset, to move to that offset before
+ * data stream from the provider or {@code null} if the provider recently crashed.
+ * Note that this may be a pipe, meaning you can't seek in it. The only seek you
+ * should do is if the AssetFileDescriptor contains an offset, to move to that offset before
* reading. You own this descriptor and are responsible for closing it when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
@@ -1938,9 +1945,9 @@
* or null if none. If the operation is canceled, then
* {@link OperationCanceledException} will be thrown.
* @return Returns a new ParcelFileDescriptor from which you can read the
- * data stream from the provider. Note that this may be a pipe, meaning
- * you can't seek in it. The only seek you should do is if the
- * AssetFileDescriptor contains an offset, to move to that offset before
+ * data stream from the provider or {@code null} if the provider recently crashed.
+ * Note that this may be a pipe, meaning you can't seek in it. The only seek you
+ * should do is if the AssetFileDescriptor contains an offset, to move to that offset before
* reading. You own this descriptor and are responsible for closing it when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 09c6849..8472144 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3639,7 +3639,6 @@
* @see android.telephony.CarrierConfigManager
* @see #EUICC_SERVICE
* @see android.telephony.euicc.EuiccManager
- * @see #MMS_SERVICE
* @see android.telephony.MmsManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7d8a4a4..baaf8f7 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6015,6 +6015,8 @@
FLAG_ACTIVITY_TASK_ON_HOME,
FLAG_ACTIVITY_RETAIN_IN_RECENTS,
FLAG_ACTIVITY_LAUNCH_ADJACENT,
+ FLAG_ACTIVITY_REQUIRE_NON_BROWSER,
+ FLAG_ACTIVITY_REQUIRE_DEFAULT,
FLAG_RECEIVER_REGISTERED_ONLY,
FLAG_RECEIVER_REPLACE_PENDING,
FLAG_RECEIVER_FOREGROUND,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index bbcac56..4299e80 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1870,7 +1870,7 @@
* an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
* respectively to the default launcher app.
*
- * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
+ * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.</h3>
*
* <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
* {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
@@ -1887,7 +1887,7 @@
*
* <p>See also {@link ShortcutManager} for more details.
*
- * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
+ * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.</h3>
*
* <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
* an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5795cd2..4d718ef 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -47,8 +47,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.ArtManager;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
@@ -1561,6 +1564,14 @@
*/
public static final int INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED = -124;
+ /**
+ * Installation failed return code: the package was skipped and should be ignored.
+ *
+ * The reason for the skip is undefined.
+ * @hide
+ */
+ public static final int INSTALL_PARSE_FAILED_SKIPPED = -125;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -6029,28 +6040,24 @@
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
@PackageInfoFlags int flags) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(this));
- final File apkFile = new File(archiveFilePath);
- try {
- if ((flags & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
- // Caller expressed an explicit opinion about what encryption
- // aware/unaware components they want to see, so fall through and
- // give them what they want
- } else {
- // Caller expressed no opinion, so match everything
- flags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
- }
+ if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
+ // Caller expressed no opinion about what encryption
+ // aware/unaware components they want to see, so match both
+ flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
- PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
- if ((flags & GET_SIGNATURES) != 0) {
- PackageParser.collectCertificates(pkg, false /* skipVerify */);
- }
- PackageUserState state = new PackageUserState();
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
- } catch (PackageParserException e) {
+ boolean collectCertificates = (flags & PackageManager.GET_SIGNATURES) != 0
+ || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0;
+
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ new File(archiveFilePath), 0, collectCertificates);
+ if (result.isError()) {
return null;
}
+ return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flags, 0, 0, null,
+ new PackageUserState(), UserHandle.getCallingUserId());
}
/**
@@ -7940,7 +7947,6 @@
*
* @return true if the drawable represents the default activity icon, false otherwise
* @see #getDefaultActivityIcon()
- * @see PackageItemInfo#loadDefaultIcon(PackageManager)
* @see #getActivityIcon
* @see LauncherActivityInfo#getIcon(int)
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index addac98..312e98e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,6 +1517,10 @@
? null : "must have at least one '.' separator";
}
+ /**
+ * @deprecated Use {@link android.content.pm.parsing.ApkLiteParseUtils#parsePackageSplitNames}
+ */
+ @Deprecated
public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
AttributeSet attrs) throws IOException, XmlPullParserException,
PackageParserException {
@@ -2001,6 +2005,7 @@
Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and "
+ pkg.baseCodePath+ ": overlay ignored due to required system property: "
+ propName + " with value: " + propValue);
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_SKIPPED;
return null;
}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 2f416a2..d2172d3 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -16,6 +16,8 @@
package android.content.pm.parsing;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.compat.annotation.UnsupportedAppUsage;
@@ -23,6 +25,8 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.VerifierInfo;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.ApkAssets;
import android.content.res.XmlResourceParser;
import android.os.Trace;
@@ -70,82 +74,93 @@
*
* @see PackageParser#parsePackage(File, int)
*/
- @UnsupportedAppUsage
- public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parsePackageLite(ParseInput input,
+ File packageFile, int flags) {
if (packageFile.isDirectory()) {
- return parseClusterPackageLite(packageFile, flags);
+ return parseClusterPackageLite(input, packageFile, flags);
} else {
- return parseMonolithicPackageLite(packageFile, flags);
+ return parseMonolithicPackageLite(input, packageFile, flags);
}
}
- public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseMonolithicPackageLite(
+ ParseInput input, File packageFile, int flags) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
- final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
- final String packagePath = packageFile.getAbsolutePath();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
- null, null);
+ try {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, packageFile, flags);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ final PackageParser.ApkLite baseApk = result.getResult();
+ final String packagePath = packageFile.getAbsolutePath();
+ return input.success(
+ new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+ null, null));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
- public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
- throws PackageParser.PackageParserException {
+ public static ParseResult<PackageParser.PackageLite> parseClusterPackageLite(ParseInput input,
+ File packageDir, int flags) {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ "No packages found in split");
}
// Apk directory is directly nested under the current directory
if (files.length == 1 && files[0].isDirectory()) {
- return parseClusterPackageLite(files[0], flags);
+ return parseClusterPackageLite(input, files[0], flags);
}
String packageName = null;
int versionCode = 0;
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
- for (File file : files) {
- if (PackageParser.isApkFile(file)) {
- final PackageParser.ApkLite lite = parseApkLite(file, flags);
-
- // Assert that all package names and version codes are
- // consistent with the first one we encounter.
- if (packageName == null) {
- packageName = lite.packageName;
- versionCode = lite.versionCode;
- } else {
- if (!packageName.equals(lite.packageName)) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent package " + lite.packageName + " in " + file
- + "; expected " + packageName);
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+ try {
+ for (File file : files) {
+ if (PackageParser.isApkFile(file)) {
+ ParseResult<PackageParser.ApkLite> result = parseApkLite(input, file, flags);
+ if (result.isError()) {
+ return input.error(result);
}
- if (versionCode != lite.versionCode) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent version " + lite.versionCode + " in " + file
- + "; expected " + versionCode);
- }
- }
- // Assert that each split is defined only oncuses-static-libe
- if (apks.put(lite.splitName, lite) != null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Split name " + lite.splitName
- + " defined more than once; most recent was " + file);
+ final PackageParser.ApkLite lite = result.getResult();
+ // Assert that all package names and version codes are
+ // consistent with the first one we encounter.
+ if (packageName == null) {
+ packageName = lite.packageName;
+ versionCode = lite.versionCode;
+ } else {
+ if (!packageName.equals(lite.packageName)) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent package " + lite.packageName + " in " + file
+ + "; expected " + packageName);
+ }
+ if (versionCode != lite.versionCode) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent version " + lite.versionCode + " in " + file
+ + "; expected " + versionCode);
+ }
+ }
+
+ // Assert that each split is defined only oncuses-static-libe
+ if (apks.put(lite.splitName, lite) != null) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split name " + lite.splitName
+ + " defined more than once; most recent was " + file);
+ }
}
}
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final PackageParser.ApkLite baseApk = apks.remove(null);
if (baseApk == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Missing base APK in " + packageDir);
}
@@ -180,8 +195,9 @@
}
final String codePath = packageDir.getAbsolutePath();
- return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
- usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+ return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
+ isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
+ splitRevisionCodes));
}
/**
@@ -192,9 +208,9 @@
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
- throws PackageParser.PackageParserException {
- return parseApkLiteInner(apkFile, null, null, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input, File apkFile,
+ int flags) {
+ return parseApkLiteInner(input, apkFile, null, null, flags);
}
/**
@@ -206,13 +222,13 @@
* @param flags optional parse flags, such as
* {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
*/
- public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
- int flags) throws PackageParser.PackageParserException {
- return parseApkLiteInner(null, fd, debugPathName, flags);
+ public static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
+ FileDescriptor fd, String debugPathName, int flags) {
+ return parseApkLiteInner(input, null, fd, debugPathName, flags);
}
- private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
- String debugPathName, int flags) throws PackageParser.PackageParserException {
+ private static ParseResult<PackageParser.ApkLite> parseApkLiteInner(ParseInput input,
+ File apkFile, FileDescriptor fd, String debugPathName, int flags) {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
XmlResourceParser parser = null;
@@ -223,8 +239,7 @@
? ApkAssets.loadFromFd(fd, debugPathName, 0 /* flags */, null /* assets */)
: ApkAssets.loadFromPath(apkPath);
} catch (IOException e) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath, e);
}
@@ -235,9 +250,15 @@
final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(),
- skipVerify, false, PackageParser.SigningDetails.UNKNOWN,
- DEFAULT_TARGET_SDK_VERSION);
+ ParseResult<PackageParser.SigningDetails> result =
+ ParsingPackageUtils.getSigningDetails(input,
+ apkFile.getAbsolutePath(), skipVerify, false,
+ PackageParser.SigningDetails.UNKNOWN,
+ DEFAULT_TARGET_SDK_VERSION);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ signingDetails = result.getResult();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -246,12 +267,10 @@
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, parser, attrs, signingDetails);
-
+ return parseApkLite(input, apkPath, parser, attrs, signingDetails);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
@@ -265,12 +284,16 @@
}
}
- private static PackageParser.ApkLite parseApkLite(
+ private static ParseResult<PackageParser.ApkLite> parseApkLite(ParseInput input,
String codePath, XmlPullParser parser, AttributeSet attrs,
PackageParser.SigningDetails signingDetails)
- throws IOException, XmlPullParserException, PackageParser.PackageParserException {
- final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
- parser, attrs);
+ throws IOException, XmlPullParserException {
+ ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs);
+ if (result.isError()) {
+ return input.error(result);
+ }
+
+ Pair<String, String> packageSplit = result.getResult();
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
@@ -394,8 +417,7 @@
usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
if (usesSplitName == null) {
- throw new PackageParser.PackageParserException(
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"<uses-split> tag requires 'android:name' attribute");
}
} else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
@@ -423,12 +445,54 @@
overlayPriority = 0;
}
- return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
- isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
- versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
- coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
- isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
- targetSdkVersion);
+ return input.success(new PackageParser.ApkLite(codePath, packageSplit.first,
+ packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired,
+ versionCode, versionCodeMajor, revisionCode, installLocation, verifiers,
+ signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex,
+ extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority,
+ minSdkVersion, targetSdkVersion));
+ }
+
+ public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
+ XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No start tag found");
+ }
+ if (!parser.getName().equals(PackageParser.TAG_MANIFEST)) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No <manifest> tag");
+ }
+
+ final String packageName = attrs.getAttributeValue(null, "package");
+ if (!"android".equals(packageName)) {
+ final String error = PackageParser.validateName(packageName, true, true);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest package: " + error);
+ }
+ }
+
+ String splitName = attrs.getAttributeValue(null, "split");
+ if (splitName != null) {
+ if (splitName.length() == 0) {
+ splitName = null;
+ } else {
+ final String error = PackageParser.validateName(splitName, false, false);
+ if (error != null) {
+ return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest split: " + error);
+ }
+ }
+ }
+
+ return input.success(Pair.create(packageName.intern(),
+ (splitName != null) ? splitName.intern() : splitName));
}
public static VerifierInfo parseVerifier(AttributeSet attrs) {
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 197ad74..cb29431 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -29,6 +29,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.AnyRes;
+import android.annotation.CheckResult;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -135,23 +136,32 @@
* for feature support.
*/
@NonNull
- public static ParseResult<ParsingPackage> parseDefaultOneTime(File file, int flags,
- @NonNull ParseInput.Callback inputCallback, @NonNull Callback callback) {
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
- // Caller expressed no opinion about what encryption
- // aware/unaware components they want to see, so match both
- flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- }
-
- ParseInput input = new ParseTypeImpl(inputCallback).reset();
+ public static ParseResult<ParsingPackage> parseDefaultOneTime(File file,
+ @PackageParser.ParseFlags int parseFlags, boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
ParseResult<ParsingPackage> result;
+ ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, new Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission parsing
+ // and will force <uses-permission/> declarations to include all requiredNotFeature
+ // permissions and exclude all requiredFeature permissions. This mirrors the old
+ // behavior.
+ return false;
+ }
- ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, callback);
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseCodePath,
+ @NonNull String codePath,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return new ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray);
+ }
+ });
try {
- result = parser.parsePackage(input, file, flags);
+ result = parser.parsePackage(input, file, parseFlags);
if (result.isError()) {
return result;
}
@@ -162,9 +172,9 @@
try {
ParsingPackage pkg = result.getResult();
- if ((flags & PackageManager.GET_SIGNATURES) != 0
- || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
- ParsingPackageUtils.collectCertificates(pkg, false /* skipVerify */);
+ if (collectCertificates) {
+ pkg.setSigningDetails(
+ ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */));
}
return input.success(pkg);
@@ -197,7 +207,7 @@
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -223,12 +233,17 @@
* split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
- int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
- 0);
+ int flags) {
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + packageDir);
@@ -275,6 +290,9 @@
pkg.setUse32BitAbi(lite.use32bitAbi);
return input.success(pkg);
+ } catch (PackageParserException e) {
+ return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Failed to load assets: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -284,12 +302,17 @@
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
+ * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
- final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
- flags);
+ ParseResult<PackageParser.PackageLite> liteResult =
+ ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
+ if (liteResult.isError()) {
+ return input.error(liteResult);
+ }
+
+ final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + apkFile);
@@ -373,8 +396,13 @@
}
}
- pkg.setVolumeUuid(volumeUuid)
- .setSigningDetails(SigningDetails.UNKNOWN);
+ pkg.setVolumeUuid(volumeUuid);
+
+ if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
+ pkg.setSigningDetails(getSigningDetails(pkg, false));
+ } else {
+ pkg.setSigningDetails(SigningDetails.UNKNOWN);
+ }
return input.success(pkg);
} catch (Exception e) {
@@ -426,24 +454,25 @@
*/
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException, PackageParserException {
final String splitName;
final String pkgName;
- try {
- Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
- parser);
- pkgName = packageSplit.first;
- splitName = packageSplit.second;
+ ParseResult<Pair<String, String>> packageSplitResult =
+ ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
+ if (packageSplitResult.isError()) {
+ return input.error(packageSplitResult);
+ }
- if (!TextUtils.isEmpty(splitName)) {
- return input.error(
- PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Expected base APK, but found split " + splitName
- );
- }
- } catch (PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+ Pair<String, String> packageSplit = packageSplitResult.getResult();
+ pkgName = packageSplit.first;
+ splitName = packageSplit.second;
+
+ if (!TextUtils.isEmpty(splitName)) {
+ return input.error(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Expected base APK, but found split " + splitName
+ );
}
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
@@ -2347,14 +2376,12 @@
String propValue = sa.getString(
R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
if (!PackageParser.checkRequiredSystemProperties(propName, propValue)) {
- Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
+ String message = "Skipping target and overlay pair " + target + " and "
+ pkg.getBaseCodePath()
+ ": overlay ignored due to required system property: "
- + propName + " with value: " + propValue);
- return input.error("Skipping target and overlay pair " + target + " and "
- + pkg.getBaseCodePath()
- + ": overlay ignored due to required system property: "
- + propName + " with value: " + propValue);
+ + propName + " with value: " + propValue;
+ Slog.i(TAG, message);
+ return input.skip(message);
}
return input.success(pkg.setOverlay(true)
@@ -2626,31 +2653,53 @@
/**
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
+ *
+ * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
+ * call if requested. Leaving this as an optional method for the caller means we have to
+ * construct a dummy ParseInput.
*/
- public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
+ @CheckResult
+ public static SigningDetails getSigningDetails(ParsingPackageRead pkg, boolean skipVerify)
throws PackageParserException {
SigningDetails signingDetails = SigningDetails.UNKNOWN;
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- signingDetails = collectCertificates(
+ ParseResult<SigningDetails> result = getSigningDetails(
+ input,
pkg.getBaseCodePath(),
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+ signingDetails = result.getResult();
String[] splitCodePaths = pkg.getSplitCodePaths();
if (!ArrayUtils.isEmpty(splitCodePaths)) {
for (int i = 0; i < splitCodePaths.length; i++) {
- signingDetails = collectCertificates(
+ result = getSigningDetails(
+ input,
splitCodePaths[i],
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
+ if (result.isError()) {
+ throw new PackageParser.PackageParserException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
+ }
+
+
+ signingDetails = result.getResult();
}
}
return signingDetails;
@@ -2659,9 +2708,10 @@
}
}
- public static SigningDetails collectCertificates(String baseCodePath, boolean skipVerify,
- boolean isStaticSharedLibrary, @NonNull SigningDetails existingSigningDetails,
- int targetSdk) throws PackageParserException {
+ @CheckResult
+ public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
+ String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
+ @NonNull SigningDetails existingSigningDetails, int targetSdk) {
int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
targetSdk);
if (isStaticSharedLibrary) {
@@ -2669,27 +2719,31 @@
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
- if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying
- verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- baseCodePath, minSignatureScheme);
- } else {
- verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ try {
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ baseCodePath, minSignatureScheme);
+ } else {
+ verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+ }
+ } catch (PackageParserException e) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed collecting certificates for " + baseCodePath, e);
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
if (existingSigningDetails == SigningDetails.UNKNOWN) {
- return verified;
+ return input.success(verified);
} else {
if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
baseCodePath + " has mismatched certificates");
}
- return existingSigningDetails;
+ return input.success(existingSigningDetails);
}
}
diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java
index 6b659be..d5898b7 100644
--- a/core/java/android/content/pm/parsing/result/ParseInput.java
+++ b/core/java/android/content/pm/parsing/result/ParseInput.java
@@ -88,6 +88,14 @@
*/
ParseResult<?> enableDeferredError(String packageName, int targetSdkVersion);
+ /**
+ * This will assign errorCode to {@link PackageManager#INSTALL_PARSE_FAILED_SKIPPED, used for
+ * packages which should be ignored by the caller.
+ *
+ * @see #error(int, String, Exception)
+ */
+ <ResultType> ParseResult<ResultType> skip(@NonNull String parseError);
+
/** @see #error(int, String, Exception) */
<ResultType> ParseResult<ResultType> error(int parseError);
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index b26bf71..91e571b 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -18,12 +18,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingUtils;
+import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.CollectionUtils;
/** @hide */
@@ -61,6 +65,28 @@
private Integer mTargetSdkVersion;
/**
+ * Assumes {@link Context#PLATFORM_COMPAT_SERVICE} is available to the caller. For use
+ * with {@link android.content.pm.parsing.ApkLiteParseUtils} or similar where parsing is
+ * done outside of {@link com.android.server.pm.PackageManagerService}.
+ */
+ public static ParseTypeImpl forDefaultParsing() {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
+ });
+ }
+
+ /**
* @param callback if nullable, fallback to manual targetSdk > Q check
*/
public ParseTypeImpl(@NonNull Callback callback) {
@@ -147,6 +173,11 @@
}
@Override
+ public <ResultType> ParseResult<ResultType> skip(@NonNull String parseError) {
+ return error(PackageManager.INSTALL_PARSE_FAILED_SKIPPED, parseError);
+ }
+
+ @Override
public <ResultType> ParseResult<ResultType> error(int parseError) {
return error(parseError, null);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 7615b87c..6d49add 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -825,6 +825,7 @@
if (surface == null) throw new IllegalArgumentException("Surface is null");
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
final List<Surface> surfaces = mConfiguredOutputs.valueAt(i).getSurfaces();
@@ -847,6 +848,7 @@
maxCount);
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
@@ -865,6 +867,7 @@
public void updateOutputConfiguration(OutputConfiguration config)
throws CameraAccessException {
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
if (config.getSurface() == mConfiguredOutputs.valueAt(i).getSurface()) {
@@ -895,6 +898,7 @@
CameraOfflineSession ret;
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
if (mOfflineSessionImpl != null) {
throw new IllegalStateException("Switch to offline mode already in progress");
}
@@ -987,6 +991,7 @@
if (surface == null) throw new IllegalArgumentException("Surface is null");
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
@@ -1009,6 +1014,8 @@
}
synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
+
for (OutputConfiguration config : outputConfigs) {
int streamId = -1;
for (int i = 0; i < mConfiguredOutputs.size(); i++) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 786db6e..986e6ea 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -71,6 +71,8 @@
import android.util.Range;
import android.util.Size;
+import dalvik.annotation.optimization.FastNative;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -356,7 +358,7 @@
*/
public CameraMetadataNative(CameraMetadataNative other) {
super();
- mMetadataPtr = nativeAllocateCopy(other);
+ mMetadataPtr = nativeAllocateCopy(other.mMetadataPtr);
if (mMetadataPtr == 0) {
throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
}
@@ -398,7 +400,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- nativeWriteToParcel(dest);
+ nativeWriteToParcel(dest, mMetadataPtr);
}
/**
@@ -440,7 +442,7 @@
}
public void readFromParcel(Parcel in) {
- nativeReadFromParcel(in);
+ nativeReadFromParcel(in, mMetadataPtr);
}
/**
@@ -528,9 +530,9 @@
public static final int NUM_TYPES = 6;
private void close() {
- // this sets mMetadataPtr to 0
- nativeClose();
- mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
+ // Delete native pointer, but does not clear it
+ nativeClose(mMetadataPtr);
+ mMetadataPtr = 0;
}
private <T> T getBase(CameraCharacteristics.Key<T> key) {
@@ -550,7 +552,7 @@
if (key.hasTag()) {
tag = key.getTag();
} else {
- tag = nativeGetTagFromKeyLocal(key.getName());
+ tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName());
key.cacheTag(tag);
}
byte[] values = readValues(tag);
@@ -560,14 +562,14 @@
if (key.mFallbackName == null) {
return null;
}
- tag = nativeGetTagFromKeyLocal(key.mFallbackName);
+ tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.mFallbackName);
values = readValues(tag);
if (values == null) {
return null;
}
}
- int nativeType = nativeGetTypeFromTagLocal(tag);
+ int nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag);
Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
return marshaler.unmarshal(buffer);
@@ -1514,7 +1516,7 @@
if (key.hasTag()) {
tag = key.getTag();
} else {
- tag = nativeGetTagFromKeyLocal(key.getName());
+ tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName());
key.cacheTag(tag);
}
if (value == null) {
@@ -1523,7 +1525,7 @@
return;
} // else update the entry to a new value
- int nativeType = nativeGetTypeFromTagLocal(tag);
+ int nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag);
Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
int size = marshaler.calculateMarshalSize(value);
@@ -1684,32 +1686,47 @@
@UnsupportedAppUsage
private long mMetadataPtr; // native std::shared_ptr<CameraMetadata>*
- private native long nativeAllocate();
- private native long nativeAllocateCopy(CameraMetadataNative other)
+ @FastNative
+ private static native long nativeAllocate();
+ @FastNative
+ private static native long nativeAllocateCopy(long ptr)
throws NullPointerException;
- private native synchronized void nativeWriteToParcel(Parcel dest);
- private native synchronized void nativeReadFromParcel(Parcel source);
- private native synchronized void nativeSwap(CameraMetadataNative other)
+ @FastNative
+ private static synchronized native void nativeWriteToParcel(Parcel dest, long ptr);
+ @FastNative
+ private static synchronized native void nativeReadFromParcel(Parcel source, long ptr);
+ @FastNative
+ private static synchronized native void nativeSwap(long ptr, long otherPtr)
throws NullPointerException;
- private native synchronized void nativeClose();
- private native synchronized boolean nativeIsEmpty();
- private native synchronized int nativeGetEntryCount();
+ @FastNative
+ private static synchronized native void nativeClose(long ptr);
+ @FastNative
+ private static synchronized native boolean nativeIsEmpty(long ptr);
+ @FastNative
+ private static synchronized native int nativeGetEntryCount(long ptr);
@UnsupportedAppUsage
- private native synchronized byte[] nativeReadValues(int tag);
- private native synchronized void nativeWriteValues(int tag, byte[] src);
- private native synchronized void nativeDump() throws IOException; // dump to ALOGD
+ @FastNative
+ private static synchronized native byte[] nativeReadValues(int tag, long ptr);
+ @FastNative
+ private static synchronized native void nativeWriteValues(int tag, byte[] src, long ptr);
+ private static synchronized native void nativeDump(long ptr) throws IOException; // dump to LOGD
- private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass);
+ @FastNative
+ private static synchronized native ArrayList nativeGetAllVendorKeys(long ptr, Class keyClass);
@UnsupportedAppUsage
- private native synchronized int nativeGetTagFromKeyLocal(String keyName)
+ @FastNative
+ private static synchronized native int nativeGetTagFromKeyLocal(long ptr, String keyName)
throws IllegalArgumentException;
@UnsupportedAppUsage
- private native synchronized int nativeGetTypeFromTagLocal(int tag)
+ @FastNative
+ private static synchronized native int nativeGetTypeFromTagLocal(long ptr, int tag)
throws IllegalArgumentException;
+ @FastNative
private static native int nativeGetTagFromKey(String keyName, long vendorId)
throws IllegalArgumentException;
+ @FastNative
private static native int nativeGetTypeFromTag(int tag, long vendorId)
throws IllegalArgumentException;
@@ -1723,7 +1740,7 @@
* @hide
*/
public void swap(CameraMetadataNative other) {
- nativeSwap(other);
+ nativeSwap(mMetadataPtr, other.mMetadataPtr);
mCameraId = other.mCameraId;
mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams;
mDisplaySize = other.mDisplaySize;
@@ -1733,7 +1750,7 @@
* @hide
*/
public int getEntryCount() {
- return nativeGetEntryCount();
+ return nativeGetEntryCount(mMetadataPtr);
}
/**
@@ -1742,12 +1759,12 @@
* @hide
*/
public boolean isEmpty() {
- return nativeIsEmpty();
+ return nativeIsEmpty(mMetadataPtr);
}
/**
- * Retrieves the pointer to the native CameraMetadata as a Java long.
+ * Retrieves the pointer to the native shared_ptr<CameraMetadata> as a Java long.
*
* @hide
*/
@@ -1764,7 +1781,7 @@
if (keyClass == null) {
throw new NullPointerException();
}
- return (ArrayList<K>) nativeGetAllVendorKeys(keyClass);
+ return (ArrayList<K>) nativeGetAllVendorKeys(mMetadataPtr, keyClass);
}
/**
@@ -1816,7 +1833,7 @@
* @hide
*/
public void writeValues(int tag, byte[] src) {
- nativeWriteValues(tag, src);
+ nativeWriteValues(tag, src, mMetadataPtr);
}
/**
@@ -1832,7 +1849,7 @@
*/
public byte[] readValues(int tag) {
// TODO: Optimization. Native code returns a ByteBuffer instead.
- return nativeReadValues(tag);
+ return nativeReadValues(tag, mMetadataPtr);
}
/**
@@ -1845,7 +1862,7 @@
*/
public void dumpToLog() {
try {
- nativeDump();
+ nativeDump(mMetadataPtr);
} catch (IOException e) {
Log.wtf(TAG, "Dump logging failed", e);
}
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index afa6303..836624b 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -803,7 +803,7 @@
* @param isMetered {@code true} if the VPN network should be treated as metered regardless
* of underlying network meteredness. Defaults to {@code true}.
* @return this {@link Builder} object to facilitate chaining of method calls
- * @see NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+ * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED
*/
@NonNull
public Builder setMetered(boolean isMetered) {
diff --git a/core/java/android/net/TelephonyNetworkSpecifier.java b/core/java/android/net/TelephonyNetworkSpecifier.java
index aafebd7..33c71d5 100644
--- a/core/java/android/net/TelephonyNetworkSpecifier.java
+++ b/core/java/android/net/TelephonyNetworkSpecifier.java
@@ -98,9 +98,10 @@
/** @hide */
@Override
public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- // Any generic requests should be satisfied by a specific telephony network.
- // For simplicity, we treat null same as MatchAllNetworkSpecifier
- return equals(other) || other == null || other instanceof MatchAllNetworkSpecifier;
+ // Although the only caller, NetworkCapabilities, already handled the case of
+ // MatchAllNetworkSpecifier, we do it again here in case the API will be used by others.
+ // TODO(b/154959809): consider implementing bi-directional specifier instead.
+ return equals(other) || other instanceof MatchAllNetworkSpecifier;
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 63e5107..9c2c5b8 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -836,7 +836,7 @@
* @param isMetered {@code true} if VPN network should be treated as metered regardless of
* underlying network meteredness
* @return this {@link Builder} object to facilitate chaining method calls
- * @see #setUnderlyingNetworks(Networks[])
+ * @see #setUnderlyingNetworks(Network[])
* @see ConnectivityManager#isActiveNetworkMetered()
*/
@NonNull
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 70b2db7..ef2a8a1 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1005,7 +1005,7 @@
/**
* R.
*/
- public static final int R = CUR_DEVELOPMENT;
+ public static final int R = 30;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
index 98f949b..8175002 100644
--- a/core/java/android/os/RegistrantList.java
+++ b/core/java/android/os/RegistrantList.java
@@ -66,6 +66,10 @@
}
}
+ public synchronized void removeAll() {
+ registrants.clear();
+ }
+
@UnsupportedAppUsage
public synchronized int
size()
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index e8af564..02b822a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1022,7 +1022,6 @@
* behaviors or empty states. Instead, apps should store data needed
* while a user is locked under device protected storage areas.
*
- * @see Context#createCredentialProtectedStorageContext()
* @see Context#createDeviceProtectedStorageContext()
*/
public @NonNull Builder detectCredentialProtectedWhileLocked() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 187274a..7912dac 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -635,10 +635,11 @@
/**
* Specifies if a user is disallowed from adding new users. This can only be set by device
- * owners, profile owners on the primary user or profile owners of organization-owned managed
- * profiles on the parent profile. The default value is <code>false</code>.
+ * owners or profile owners on the primary user. The default value is <code>false</code>.
* <p>This restriction has no effect on secondary users and managed profiles since only the
* primary user can add other users.
+ * <p> When the device is an organization-owned device provisioned with a managed profile,
+ * this restriction will be set as a base restriction which cannot be removed by any admin.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 1fef071..fd7cdda 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -64,21 +64,16 @@
/**
* A click effect. Use this effect as a baseline, as it's the most common type of click effect.
- *
- * @see #get(int)
*/
public static final int EFFECT_CLICK = Effect.CLICK;
/**
* A double click effect.
- *
- * @see #get(int)
*/
public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
/**
* A tick effect. This effect is less strong compared to {@link #EFFECT_CLICK}.
- * @see #get(int)
*/
public static final int EFFECT_TICK = Effect.TICK;
@@ -102,7 +97,6 @@
/**
* A heavy click effect. This effect is stronger than {@link #EFFECT_CLICK}.
- * @see #get(int)
*/
public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
diff --git a/core/java/android/os/strictmode/CredentialProtectedWhileLockedViolation.java b/core/java/android/os/strictmode/CredentialProtectedWhileLockedViolation.java
index 12503f6..89cd430 100644
--- a/core/java/android/os/strictmode/CredentialProtectedWhileLockedViolation.java
+++ b/core/java/android/os/strictmode/CredentialProtectedWhileLockedViolation.java
@@ -28,7 +28,6 @@
* store data needed while a user is locked under device protected storage
* areas.
*
- * @see Context#createCredentialProtectedStorageContext()
* @see Context#createDeviceProtectedStorageContext()
*/
public final class CredentialProtectedWhileLockedViolation extends Violation {
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index ed429dd..06caa03 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -56,10 +56,15 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.RemoteStream;
import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.TransferPipe;
import com.android.internal.util.CollectionUtils;
import libcore.util.EmptyArray;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -67,7 +72,9 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
@@ -476,6 +483,36 @@
}
/**
+ * Dump permission controller state.
+ *
+ * @hide
+ */
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args) {
+ CompletableFuture<Throwable> dumpResult = new CompletableFuture<>();
+ mRemoteService.postForResult(
+ service -> TransferPipe.dumpAsync(service.asBinder(), args))
+ .whenComplete(
+ (dump, err) -> {
+ try (FileOutputStream out = new FileOutputStream(fd)) {
+ out.write(dump);
+ } catch (IOException | NullPointerException e) {
+ Log.e(TAG, "Could for forwards permission controller dump", e);
+ }
+
+ dumpResult.complete(err);
+ });
+
+ try {
+ Throwable err = dumpResult.get(UNBIND_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ if (err != null) {
+ throw err;
+ }
+ } catch (Throwable e) {
+ Log.e(TAG, "Could not dump permission controller state", e);
+ }
+ }
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 82a7d78..c6ede32 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -50,9 +50,11 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -494,6 +496,11 @@
"packageName cannot be null");
onOneTimePermissionSessionTimeout(packageName);
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ PermissionControllerService.this.dump(fd, writer, args);
+ }
};
}
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 9c6c92a..17fae1c 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -797,7 +797,6 @@
* to changes.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
- * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
*/
@NonNull
public static final Uri ENTERPRISE_CONTENT_URI =
@@ -1796,7 +1795,6 @@
* to changes.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
- * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
*/
@NonNull
public static final Uri ENTERPRISE_CONTENT_URI =
@@ -2010,7 +2008,6 @@
* {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
- * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
*/
@NonNull
public static final Uri ENTERPRISE_CONTENT_URI =
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index a10a456..75840a5 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -24,7 +24,6 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ContentInterface;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -251,14 +250,14 @@
* Get string array identifies the type or types of metadata returned
* using DocumentsContract#getDocumentMetadata.
*
- * @see #getDocumentMetadata(ContentInterface, Uri)
+ * @see #getDocumentMetadata(ContentResolver, Uri)
*/
public static final String METADATA_TYPES = "android:documentMetadataTypes";
/**
* Get Exif information using DocumentsContract#getDocumentMetadata.
*
- * @see #getDocumentMetadata(ContentInterface, Uri)
+ * @see #getDocumentMetadata(ContentResolver, Uri)
*/
public static final String METADATA_EXIF = "android:documentExif";
@@ -266,7 +265,7 @@
* Get total count of all documents currently stored under the given
* directory tree. Only valid for {@link Document#MIME_TYPE_DIR} documents.
*
- * @see #getDocumentMetadata(ContentInterface, Uri)
+ * @see #getDocumentMetadata(ContentResolver, Uri)
*/
public static final String METADATA_TREE_COUNT = "android:metadataTreeCount";
@@ -274,7 +273,7 @@
* Get total size of all documents currently stored under the given
* directory tree. Only valid for {@link Document#MIME_TYPE_DIR} documents.
*
- * @see #getDocumentMetadata(ContentInterface, Uri)
+ * @see #getDocumentMetadata(ContentResolver, Uri)
*/
public static final String METADATA_TREE_SIZE = "android:metadataTreeSize";
@@ -405,7 +404,7 @@
* Flag indicating that a document can be represented as a thumbnail.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#getDocumentThumbnail(ContentInterface, Uri,
+ * @see DocumentsContract#getDocumentThumbnail(ContentResolver, Uri,
* Point, CancellationSignal)
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
@@ -431,7 +430,7 @@
* Flag indicating that a document is deletable.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#deleteDocument(ContentInterface, Uri)
+ * @see DocumentsContract#deleteDocument(ContentResolver, Uri)
* @see DocumentsProvider#deleteDocument(String)
*/
public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
@@ -469,7 +468,7 @@
* Flag indicating that a document can be renamed.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#renameDocument(ContentInterface, Uri, String)
+ * @see DocumentsContract#renameDocument(ContentResolver, Uri, String)
* @see DocumentsProvider#renameDocument(String, String)
*/
public static final int FLAG_SUPPORTS_RENAME = 1 << 6;
@@ -479,7 +478,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#copyDocument(ContentInterface, Uri, Uri)
+ * @see DocumentsContract#copyDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#copyDocument(String, String)
*/
public static final int FLAG_SUPPORTS_COPY = 1 << 7;
@@ -489,7 +488,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#moveDocument(ContentInterface, Uri, Uri, Uri)
+ * @see DocumentsContract#moveDocument(ContentResolver, Uri, Uri, Uri)
* @see DocumentsProvider#moveDocument(String, String, String)
*/
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
@@ -513,7 +512,7 @@
* Flag indicating that a document can be removed from a parent.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#removeDocument(ContentInterface, Uri, Uri)
+ * @see DocumentsContract#removeDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#removeDocument(String, String)
*/
public static final int FLAG_SUPPORTS_REMOVE = 1 << 10;
@@ -549,7 +548,7 @@
* using DocumentsContract#getDocumentMetadata
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#getDocumentMetadata(ContentInterface, Uri)
+ * @see DocumentsContract#getDocumentMetadata(ContentResolver, Uri)
*/
public static final int FLAG_SUPPORTS_METADATA = 1 << 14;
@@ -750,7 +749,7 @@
* Flag indicating that this root can be ejected.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#ejectRoot(ContentInterface, Uri)
+ * @see DocumentsContract#ejectRoot(ContentResolver, Uri)
* @see DocumentsProvider#ejectRoot(String)
*/
public static final int FLAG_SUPPORTS_EJECT = 1 << 5;
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 2e00c0c..327bca2 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -1274,8 +1274,6 @@
out.putParcelable(DocumentsContract.EXTRA_RESULT, path);
} else if (METHOD_GET_DOCUMENT_METADATA.equals(method)) {
- enforceReadPermissionInner(documentUri, getCallingPackage(),
- getCallingAttributionTag(), null);
return getDocumentMetadata(documentId);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b280c5d..ae88ba5 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5199,8 +5199,9 @@
/**
* Secure system settings, containing system preferences that applications
* can read but are not allowed to write. These are for preferences that
- * the user must explicitly modify through the system UI or specialized
- * APIs for those values, not modified directly by applications.
+ * the user must explicitly modify through the UI of a system app. Normal
+ * applications cannot modify the secure settings database, either directly
+ * or by calling the "put" methods that this class contains.
*/
public static final class Secure extends NameValueTable {
// NOTE: If you add new settings here, be sure to add them to
@@ -9688,6 +9689,13 @@
"hdmi_control_auto_device_off_enabled";
/**
+ * Whether or not media is shown automatically when bypassing as a heads up.
+ * @hide
+ */
+ public static final String SHOW_MEDIA_ON_QUICK_SETTINGS =
+ "qs_media_player";
+
+ /**
* The interval in milliseconds at which location requests will be throttled when they are
* coming from the background.
*
@@ -11948,8 +11956,24 @@
"adaptive_battery_management_enabled";
/**
+ * Whether or not apps are allowed into the
+ * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
+ * Type: int (0 for false, 1 for true)
+ * Default: {@value #DEFAULT_ENABLE_RESTRICTED_BUCKET}
+ *
+ * @hide
+ */
+ public static final String ENABLE_RESTRICTED_BUCKET = "enable_restricted_bucket";
+
+ /**
+ * @see #ENABLE_RESTRICTED_BUCKET
+ * @hide
+ */
+ public static final int DEFAULT_ENABLE_RESTRICTED_BUCKET = 1;
+
+ /**
* Whether or not app auto restriction is enabled. When it is enabled, settings app will
- * auto restrict the app if it has bad behavior(e.g. hold wakelock for long time).
+ * auto restrict the app if it has bad behavior (e.g. hold wakelock for long time).
*
* Type: boolean (0 for false, 1 for true)
* Default: 1
@@ -14025,6 +14049,14 @@
"zram_enabled";
/**
+ * Whether the app freezer is enabled on this device.
+ * The value of "enabled" enables the app freezer, "disabled" disables it and
+ * "device_default" will let the system decide whether to enable the freezer or not
+ * @hide
+ */
+ public static final String CACHED_APPS_FREEZER_ENABLED = "cached_apps_freezer";
+
+ /**
* Configuration flags for smart replies in notifications.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 188670d..678f43d 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -455,7 +455,7 @@
* heuristics purposes, but it should not be sent to external servers.
*
* <a name="FieldClassification"></a>
- * <h3>Metrics and field classification</h3
+ * <h3>Metrics and field classification</h3>
*
* <p>The service can call {@link #getFillEventHistory()} to get metrics representing the user
* actions, and then use these metrics to improve its heuristics.
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index c28d2bb..e274460 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -262,7 +262,7 @@
*
* @param condition condition used to trigger the updates.
* @param updates actions to be applied to the
- * {@link #CustomDescription.Builder(RemoteViews) template presentation} when the condition
+ * {@link #Builder(RemoteViews) template presentation} when the condition
* is satisfied.
*
* @return this builder
diff --git a/core/java/android/service/autofill/IInlineSuggestionUi.aidl b/core/java/android/service/autofill/IInlineSuggestionUi.aidl
new file mode 100644
index 0000000..7289853
--- /dev/null
+++ b/core/java/android/service/autofill/IInlineSuggestionUi.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.service.autofill.ISurfacePackageResultCallback;
+
+/**
+ * Interface to interact with a remote inline suggestion UI.
+ *
+ * @hide
+ */
+oneway interface IInlineSuggestionUi {
+ void getSurfacePackage(ISurfacePackageResultCallback callback);
+ void releaseSurfaceControlViewHost();
+}
diff --git a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
index 172cfef..97eb790 100644
--- a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
+++ b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
@@ -18,17 +18,19 @@
import android.content.IntentSender;
import android.os.IBinder;
+import android.service.autofill.IInlineSuggestionUi;
import android.view.SurfaceControlViewHost;
/**
- * Interface to receive events from inline suggestions.
+ * Interface to receive events from a remote inline suggestion UI.
*
* @hide
*/
oneway interface IInlineSuggestionUiCallback {
void onClick();
void onLongClick();
- void onContent(in SurfaceControlViewHost.SurfacePackage surface, int width, int height);
+ void onContent(in IInlineSuggestionUi content, in SurfaceControlViewHost.SurfacePackage surface,
+ int width, int height);
void onError();
void onTransferTouchFocusToImeWindow(in IBinder sourceInputToken, int displayId);
void onStartIntentSender(in IntentSender intentSender);
diff --git a/core/java/android/service/autofill/ISurfacePackageResultCallback.aidl b/core/java/android/service/autofill/ISurfacePackageResultCallback.aidl
new file mode 100644
index 0000000..0c2c624
--- /dev/null
+++ b/core/java/android/service/autofill/ISurfacePackageResultCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.view.SurfaceControlViewHost;
+
+/**
+ * Interface to receive a SurfaceControlViewHost.SurfacePackage.
+ *
+ * @hide
+ */
+oneway interface ISurfacePackageResultCallback {
+ void onResult(in SurfaceControlViewHost.SurfacePackage result);
+}
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
index 12376e8..974f0ea 100644
--- a/core/java/android/service/autofill/ImageTransformation.java
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -123,7 +123,7 @@
* {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
*
* @deprecated use
- * {@link #ImageTransformation.Builder(AutofillId, Pattern, int, CharSequence)} instead.
+ * {@link #Builder(AutofillId, Pattern, int, CharSequence)} instead.
*/
@Deprecated
public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId) {
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 19961e5..3ea443b 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -33,6 +33,7 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
+import android.util.LruCache;
import android.util.Size;
import android.view.Display;
import android.view.SurfaceControlViewHost;
@@ -40,6 +41,8 @@
import android.view.ViewGroup;
import android.view.WindowManager;
+import java.lang.ref.WeakReference;
+
/**
* A service that renders an inline presentation view given the {@link InlinePresentation}.
*
@@ -65,6 +68,27 @@
private IInlineSuggestionUiCallback mCallback;
+
+ /**
+ * A local LRU cache keeping references to the inflated {@link SurfaceControlViewHost}s, so
+ * they can be released properly when no longer used. Each view needs to be tracked separately,
+ * therefore for simplicity we use the hash code of the value object as key in the cache.
+ */
+ private final LruCache<InlineSuggestionUiImpl, Boolean> mActiveInlineSuggestions =
+ new LruCache<InlineSuggestionUiImpl, Boolean>(30) {
+ @Override
+ public void entryRemoved(boolean evicted, InlineSuggestionUiImpl key,
+ Boolean oldValue,
+ Boolean newValue) {
+ if (evicted) {
+ Log.w(TAG,
+ "Hit max=100 entries in the cache. Releasing oldest one to make "
+ + "space.");
+ key.releaseSurfaceControlViewHost();
+ }
+ }
+ };
+
/**
* If the specified {@code width}/{@code height} is an exact value, then it will be returned as
* is, otherwise the method tries to measure a size that is just large enough to fit the view
@@ -144,22 +168,24 @@
final SurfaceControlViewHost host = new SurfaceControlViewHost(this, getDisplay(),
hostInputToken);
host.setView(suggestionRoot, lp);
- suggestionRoot.setOnClickListener((v) -> {
+
+ // Set the suggestion view to be non-focusable so that if its background is set to a
+ // ripple drawable, the ripple won't be shown initially.
+ suggestionView.setFocusable(false);
+ suggestionView.setOnClickListener((v) -> {
try {
- if (suggestionView.hasOnClickListeners()) {
- suggestionView.callOnClick();
- }
callback.onClick();
} catch (RemoteException e) {
Log.w(TAG, "RemoteException calling onClick()");
}
});
-
- suggestionRoot.setOnLongClickListener((v) -> {
+ final View.OnLongClickListener onLongClickListener =
+ suggestionView.getOnLongClickListener();
+ suggestionView.setOnLongClickListener((v) -> {
+ if (onLongClickListener != null) {
+ onLongClickListener.onLongClick(v);
+ }
try {
- if (suggestionView.hasOnLongClickListeners()) {
- suggestionView.performLongClick();
- }
callback.onLongClick();
} catch (RemoteException e) {
Log.w(TAG, "RemoteException calling onLongClick()");
@@ -167,8 +193,14 @@
return true;
});
- sendResult(callback, host.getSurfacePackage(), measuredSize.getWidth(),
- measuredSize.getHeight());
+ try {
+ InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mHandler);
+ mActiveInlineSuggestions.put(uiImpl, true);
+ callback.onContent(new InlineSuggestionUiWrapper(uiImpl), host.getSurfacePackage(),
+ measuredSize.getWidth(), measuredSize.getHeight());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling onContent()");
+ }
} finally {
updateDisplay(Display.DEFAULT_DISPLAY);
}
@@ -179,12 +211,87 @@
callback.sendResult(rendererInfo);
}
- private void sendResult(@NonNull IInlineSuggestionUiCallback callback,
- @Nullable SurfaceControlViewHost.SurfacePackage surface, int width, int height) {
- try {
- callback.onContent(surface, width, height);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling onContent(" + surface + ")");
+ /**
+ * A wrapper class around the {@link InlineSuggestionUiImpl} to ensure it's not strongly
+ * reference by the remote system server process.
+ */
+ private static final class InlineSuggestionUiWrapper extends
+ android.service.autofill.IInlineSuggestionUi.Stub {
+
+ private final WeakReference<InlineSuggestionUiImpl> mUiImpl;
+
+ InlineSuggestionUiWrapper(InlineSuggestionUiImpl uiImpl) {
+ mUiImpl = new WeakReference<>(uiImpl);
+ }
+
+ @Override
+ public void releaseSurfaceControlViewHost() {
+ final InlineSuggestionUiImpl uiImpl = mUiImpl.get();
+ if (uiImpl != null) {
+ uiImpl.releaseSurfaceControlViewHost();
+ }
+ }
+
+ @Override
+ public void getSurfacePackage(ISurfacePackageResultCallback callback) {
+ final InlineSuggestionUiImpl uiImpl = mUiImpl.get();
+ if (uiImpl != null) {
+ uiImpl.getSurfacePackage(callback);
+ }
+ }
+ }
+
+ /**
+ * Keeps track of a SurfaceControlViewHost to ensure it's released when its lifecycle ends.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single
+ * handler thread to be processed.
+ */
+ private final class InlineSuggestionUiImpl {
+
+ @Nullable
+ private SurfaceControlViewHost mViewHost;
+ @NonNull
+ private final Handler mHandler;
+
+ InlineSuggestionUiImpl(SurfaceControlViewHost viewHost, Handler handler) {
+ this.mViewHost = viewHost;
+ this.mHandler = handler;
+ }
+
+ /**
+ * Call {@link SurfaceControlViewHost#release()} to release it. After this, this view is
+ * not usable, and any further calls to the
+ * {@link #getSurfacePackage(ISurfacePackageResultCallback)} will get {@code null} result.
+ */
+ public void releaseSurfaceControlViewHost() {
+ mHandler.post(() -> {
+ if (mViewHost == null) {
+ return;
+ }
+ Log.v(TAG, "Releasing inline suggestion view host");
+ mViewHost.release();
+ mViewHost = null;
+ InlineSuggestionRenderService.this.mActiveInlineSuggestions.remove(
+ InlineSuggestionUiImpl.this);
+ Log.v(TAG, "Removed the inline suggestion from the cache, current size="
+ + InlineSuggestionRenderService.this.mActiveInlineSuggestions.size());
+ });
+ }
+
+ /**
+ * Sends back a new {@link android.view.SurfaceControlViewHost.SurfacePackage} if the view
+ * is not released, {@code null} otherwise.
+ */
+ public void getSurfacePackage(ISurfacePackageResultCallback callback) {
+ Log.d(TAG, "getSurfacePackage");
+ mHandler.post(() -> {
+ try {
+ callback.onResult(mViewHost == null ? null : mViewHost.getSurfacePackage());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling onSurfacePackage");
+ }
+ });
}
}
diff --git a/core/java/android/service/autofill/InlineSuggestionRoot.java b/core/java/android/service/autofill/InlineSuggestionRoot.java
index 653e513..c879653 100644
--- a/core/java/android/service/autofill/InlineSuggestionRoot.java
+++ b/core/java/android/service/autofill/InlineSuggestionRoot.java
@@ -52,13 +52,8 @@
}
@Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return true;
- }
-
- @Override
@SuppressLint("ClickableViewAccessibility")
- public boolean onTouchEvent(@NonNull MotionEvent event) {
+ public boolean dispatchTouchEvent(@NonNull MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDownX = event.getX();
@@ -80,6 +75,6 @@
}
} break;
}
- return super.onTouchEvent(event);
+ return super.dispatchTouchEvent(event);
}
}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 4df4362..e640eec 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -719,7 +719,7 @@
*
* <p>The sanitizer can also be used as an alternative for a
* {@link #setValidator(Validator) validator}. If any of the {@code ids} is a
- * {@link #SaveInfo.Builder(int, AutofillId[]) required id} and the {@code sanitizer} fails
+ * {@link #Builder(int, AutofillId[]) required id} and the {@code sanitizer} fails
* because of it, then the save UI is not shown.
*
* @param sanitizer an implementation provided by the Android System.
@@ -777,7 +777,7 @@
* Builds a new {@link SaveInfo} instance.
*
* @throws IllegalStateException if no
- * {@link #SaveInfo.Builder(int, AutofillId[]) required ids},
+ * {@link #Builder(int, AutofillId[]) required ids},
* or {@link #setOptionalIds(AutofillId[]) optional ids}, or {@link #FLAG_DELAY_SAVE}
* were set
*/
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index cca45f5..c2234ba 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -163,14 +163,18 @@
}
/**
- * The child class of the service can call this method to initiate an Autofill flow.
+ * The child class of the service can call this method to initiate a new Autofill flow. If all
+ * conditions are met, it will make a request to the client app process to explicitly cancel
+ * the current autofill session and create a new session. For example, an augmented autofill
+ * service may notice some events which make it think a good time to provide updated
+ * augmented autofill suggestions.
*
* <p> The request would be respected only if the previous augmented autofill request was
* made for the same {@code activityComponent} and {@code autofillId}, and the field is
* currently on focus.
*
- * <p> The request would start a new autofill flow. It doesn't guarantee that the
- * {@link AutofillManager} will proceed with the request.
+ * <p> The request would cancel the current session and start a new autofill flow.
+ * It doesn't guarantee that the {@link AutofillManager} will proceed with the request.
*
* @param activityComponent the client component for which the autofill is requested for
* @param autofillId the client field id for which the autofill is requested for
@@ -179,8 +183,6 @@
*/
public final boolean requestAutofill(@NonNull ComponentName activityComponent,
@NonNull AutofillId autofillId) {
- // TODO(b/149531989): revisit this. The request should start a new autofill session
- // rather than reusing the existing session.
final AutofillProxy proxy = mAutofillProxyForLastRequest;
if (proxy == null || !proxy.mComponentName.equals(activityComponent)
|| !proxy.mFocusedId.equals(autofillId)) {
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index 0a29edc..09d1bb9 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -21,6 +21,8 @@
import android.os.Bundle;
import android.view.WindowInsets;
+import com.android.internal.R;
+
/**
* The Activity used by the {@link DreamService} to draw screensaver content
* on the screen. This activity runs in dream application's process, but is started by a
@@ -56,8 +58,20 @@
if (callback != null) {
callback.onActivityCreated(this);
}
+ }
+ @Override
+ public void onResume() {
+ super.onResume();
// Hide all insets (nav bar, status bar, etc) when the dream is showing
getWindow().getInsetsController().hide(WindowInsets.Type.systemBars());
+ overridePendingTransition(R.anim.dream_activity_open_enter,
+ R.anim.dream_activity_open_exit);
+ }
+
+ @Override
+ public void finishAndRemoveTask() {
+ super.finishAndRemoveTask();
+ overridePendingTransition(0, R.anim.dream_activity_close_exit);
}
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 337027e..d2dfb29 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1052,7 +1052,6 @@
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
@@ -1076,8 +1075,12 @@
@Override
public void onViewDetachedFromWindow(View v) {
- mActivity = null;
- finish();
+ if (mActivity == null || !mActivity.isChangingConfigurations()) {
+ // Only stop the dream if the view is not detached by relaunching
+ // activity for configuration changes.
+ mActivity = null;
+ finish();
+ }
}
});
}
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 9dfbc28..93faa58 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -424,6 +424,11 @@
return bundle.getParcelable(KEY_RESULT);
}
+ /** @hide **/
+ public static <T extends Parcelable> void putResponse(Bundle bundle, T response) {
+ bundle.putParcelable(KEY_RESULT, response);
+ }
+
/**
* Callbacks for TextClassifierService results.
*
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 92f3538..aea94bf 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -283,8 +283,8 @@
} else {
serviceIntent.setComponent(mServiceComponent);
}
-
- if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(serviceIntent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES)) {
Log.e(TAG, "bind to recognition service failed");
mConnection = null;
mService = null;
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index c36a33f..e4fbf9f 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -379,8 +379,6 @@
*
* <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see #onEmergencyNumberListChanged
*/
public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000;
@@ -459,7 +457,7 @@
* <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
* the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
- * @see #onRegistrationFailed()
+ * @see #onRegistrationFailed
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
@@ -470,7 +468,7 @@
* <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
* the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
- * @see #onBarringInfoChanged()
+ * @see #onBarringInfoChanged
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_BARRING_INFO = 0x80000000;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index cd20b35..6c619bb1 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -62,7 +62,7 @@
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true");
- DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
+ DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "true");
DEFAULT_FLAGS.put("settings_conditionals", "false");
// This flags guards a feature introduced in R and will be removed in the next release
// (b/148367230).
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 2c260f6..5fcd38e 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -2275,7 +2275,7 @@
/**
* Write an individual field tag by hand.
*
- * @see See <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * See <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
* Encoding</a> for details on the structure of how tags and data are written.
*/
public void writeTag(int id, @WireType int wireType) {
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 25e8111..926d8fc 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -342,5 +342,5 @@
* Update the flags on an input channel associated with a particular surface.
*/
void updateInputChannel(in IBinder channelToken, int displayId, in SurfaceControl surface,
- int flags);
+ int flags, in Region region);
}
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 38b6c03..8b5af29 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -143,9 +143,6 @@
public void setControl(@Nullable InsetsSourceControl control, int[] showTypes,
int[] hideTypes) {
super.setControl(control, showTypes, hideTypes);
- if (control == getControl()) {
- return;
- }
if (control == null && !mIsRequestedVisibleAwaitingControl) {
hide();
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a135b0c..2d17b6d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -667,7 +667,7 @@
if (hideTypes[0] != 0) {
applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
}
- if (hasControl) {
+ if (hasControl && mRequestedState.getSourcesCount() > 0) {
// We might have changed our requested visibilities while we don't have the control,
// so we need to update our requested state once we have control. Otherwise, our
// requested state at the server side might be incorrect.
@@ -1065,9 +1065,16 @@
if (consumer.getControl() != null) {
final InsetsSource localSource = mState.getSource(type);
if (!localSource.equals(mRequestedState.peekSource(type))) {
+ // Our requested state is stale. Update it here and send it to window manager.
mRequestedState.addSource(new InsetsSource(localSource));
changed = true;
}
+ if (!localSource.equals(mLastDispatchedState.peekSource(type))) {
+ // The server state is not what we expected. This can happen while we don't have
+ // the control. Since we have the control now, we need to send our request again
+ // to modify the server state.
+ changed = true;
+ }
}
}
if (!changed) {
@@ -1117,7 +1124,7 @@
* Cancel on-going animation to show/hide {@link InsetsType}.
*/
@VisibleForTesting
- public void cancelExistingAnimation() {
+ public void cancelExistingAnimations() {
cancelExistingControllers(all());
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0625806..c0c29eb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1464,8 +1464,23 @@
*/
public static final class DesiredDisplayConfigSpecs {
public int defaultConfig;
- public float minRefreshRate;
- public float maxRefreshRate;
+ /**
+ * The primary refresh rate range represents display manager's general guidance on the
+ * display configs surface flinger will consider when switching refresh rates. Unless
+ * surface flinger has a specific reason to do otherwise, it will stay within this range.
+ */
+ public float primaryRefreshRateMin;
+ public float primaryRefreshRateMax;
+ /**
+ * The app request refresh rate range allows surface flinger to consider more display
+ * configs when switching refresh rates. Although surface flinger will generally stay within
+ * the primary range, specific considerations, such as layer frame rate settings specified
+ * via the setFrameRate() api, may cause surface flinger to go outside the primary
+ * range. Surface flinger never goes outside the app request range. The app request range
+ * will be greater than or equal to the primary refresh rate range, never smaller.
+ */
+ public float appRequestRefreshRateMin;
+ public float appRequestRefreshRateMax;
public DesiredDisplayConfigSpecs() {}
@@ -1473,11 +1488,14 @@
copyFrom(other);
}
- public DesiredDisplayConfigSpecs(
- int defaultConfig, float minRefreshRate, float maxRefreshRate) {
+ public DesiredDisplayConfigSpecs(int defaultConfig, float primaryRefreshRateMin,
+ float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
this.defaultConfig = defaultConfig;
- this.minRefreshRate = minRefreshRate;
- this.maxRefreshRate = maxRefreshRate;
+ this.primaryRefreshRateMin = primaryRefreshRateMin;
+ this.primaryRefreshRateMax = primaryRefreshRateMax;
+ this.appRequestRefreshRateMin = appRequestRefreshRateMin;
+ this.appRequestRefreshRateMax = appRequestRefreshRateMax;
}
@Override
@@ -1490,8 +1508,10 @@
*/
public boolean equals(DesiredDisplayConfigSpecs other) {
return other != null && defaultConfig == other.defaultConfig
- && minRefreshRate == other.minRefreshRate
- && maxRefreshRate == other.maxRefreshRate;
+ && primaryRefreshRateMin == other.primaryRefreshRateMin
+ && primaryRefreshRateMax == other.primaryRefreshRateMax
+ && appRequestRefreshRateMin == other.appRequestRefreshRateMin
+ && appRequestRefreshRateMax == other.appRequestRefreshRateMax;
}
@Override
@@ -1504,14 +1524,18 @@
*/
public void copyFrom(DesiredDisplayConfigSpecs other) {
defaultConfig = other.defaultConfig;
- minRefreshRate = other.minRefreshRate;
- maxRefreshRate = other.maxRefreshRate;
+ primaryRefreshRateMin = other.primaryRefreshRateMin;
+ primaryRefreshRateMax = other.primaryRefreshRateMax;
+ appRequestRefreshRateMin = other.appRequestRefreshRateMin;
+ appRequestRefreshRateMax = other.appRequestRefreshRateMax;
}
@Override
public String toString() {
- return String.format("defaultConfig=%d min=%.0f max=%.0f", defaultConfig,
- minRefreshRate, maxRefreshRate);
+ return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
+ + " appRequestRefreshRateRange=[%.0f %.0f]",
+ defaultConfig, primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin, appRequestRefreshRateMax);
}
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 3d6da6f..7086dc0 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -234,6 +234,14 @@
}
/**
+ * @return the WindowlessWindowManager instance that this host is attached to.
+ * @hide
+ */
+ public @NonNull WindowlessWindowManager getWindowlessWM() {
+ return mWm;
+ }
+
+ /**
* @hide
*/
@TestApi
@@ -264,8 +272,8 @@
* and render the object unusable.
*/
public void release() {
+ // ViewRoot will release mSurfaceControl for us.
mViewRoot.die(false /* immediate */);
- mSurfaceControl.release();
}
/**
diff --git a/core/java/android/view/VerifiedInputEvent.java b/core/java/android/view/VerifiedInputEvent.java
index 531b3ed..e2db501 100644
--- a/core/java/android/view/VerifiedInputEvent.java
+++ b/core/java/android/view/VerifiedInputEvent.java
@@ -92,8 +92,6 @@
* time base.
*
* @see InputEvent#getEventTime()
- * @see KeyEvent#getEventTimeNano()
- * @see MotionEvent#getEventTimeNano()
*/
@SuppressLint("MethodNameUnits")
public long getEventTimeNanos() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3102999..1226202 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -981,6 +981,13 @@
*/
protected static boolean sBrokenWindowBackground;
+ /**
+ * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from
+ * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps
+ * calling {@link #requestLayout} when they need to relayout based on an insets change.
+ */
+ static boolean sForceLayoutWhenInsetsChanged;
+
/** @hide */
@IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
@Retention(RetentionPolicy.SOURCE)
@@ -5375,6 +5382,9 @@
GradientDrawable.sWrapNegativeAngleMeasurements =
targetSdkVersion >= Build.VERSION_CODES.Q;
+
+ sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R;
+
sCompatibilityDone = true;
}
}
@@ -7263,6 +7273,16 @@
}
/**
+ * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise.
+ * @hide
+ */
+ @Nullable
+ public OnLongClickListener getOnLongClickListener() {
+ ListenerInfo li = mListenerInfo;
+ return (li != null) ? li.mOnLongClickListener : null;
+ }
+
+ /**
* Register a callback to be invoked when this view is context clicked. If the view is not
* context clickable, it becomes context clickable.
*
@@ -26175,9 +26195,9 @@
/**
* Returns the View object that had been passed to the
- * {@link #View.DragShadowBuilder(View)}
+ * {@link #DragShadowBuilder(View)}
* constructor. If that View parameter was {@code null} or if the
- * {@link #View.DragShadowBuilder()}
+ * {@link #DragShadowBuilder()}
* constructor was used to instantiate the builder object, this method will return
* null.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b74c8f6..a17af6c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1584,6 +1584,11 @@
mApplyInsetsRequested = true;
requestLayout();
+ // See comment for View.sForceLayoutWhenInsetsChanged
+ if (View.sForceLayoutWhenInsetsChanged && mView != null) {
+ forceLayout(mView);
+ }
+
// If this changes during traversal, no need to schedule another one as it will dispatch it
// during the current traversal.
if (!mIsInTraversal) {
@@ -4619,6 +4624,8 @@
setAccessibilityFocus(null, null);
+ mInsetsController.cancelExistingAnimations();
+
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index d8bf58f..9674a80 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -104,10 +104,10 @@
@Override
public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
+ if (mViewRoot.mView == null) {
+ throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
+ }
if (mApplier == null) {
- if (mViewRoot.mView == null) {
- throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
- }
mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
}
if (mViewRoot.mView.isHardwareAccelerated()) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index b153648..446e7aa 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -26,6 +26,7 @@
import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -1795,6 +1796,24 @@
public abstract @NonNull View getDecorView();
/**
+ * @return the status bar background view or null.
+ * @hide
+ */
+ @TestApi
+ public @Nullable View getStatusBarBackgroundView() {
+ return null;
+ }
+
+ /**
+ * @return the navigation bar background view or null.
+ * @hide
+ */
+ @TestApi
+ public @Nullable View getNavigationBarBackgroundView() {
+ return null;
+ }
+
+ /**
* Retrieve the current decor view, but only if it has already been created;
* otherwise returns null.
*
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e4dbd637..9a3c706 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -700,7 +700,6 @@
* @see #TYPE_TOAST
* @see #TYPE_SYSTEM_OVERLAY
* @see #TYPE_PRIORITY_PHONE
- * @see #TYPE_STATUS_BAR_PANEL
* @see #TYPE_SYSTEM_DIALOG
* @see #TYPE_KEYGUARD_DIALOG
* @see #TYPE_SYSTEM_ERROR
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 397bce4..15604a2 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -16,16 +16,19 @@
package android.view;
+import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.MergedConfiguration;
import java.util.HashMap;
+import java.util.Objects;
/**
* A simplistic implementation of IWindowSession. Rather than managing Surfaces
@@ -38,10 +41,12 @@
private final static String TAG = "WindowlessWindowManager";
private class State {
+ //TODO : b/150190730 we should create it when view show and release it when view invisible.
SurfaceControl mSurfaceControl;
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
int mDisplayId;
IBinder mInputChannelToken;
+ Region mInputRegion;
State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId,
IBinder inputChannelToken) {
mSurfaceControl = sc;
@@ -95,6 +100,30 @@
mResizeCompletionForWindow.put(window, callback);
}
+ protected void setTouchRegion(IBinder window, @Nullable Region region) {
+ State state;
+ synchronized (this) {
+ // Do everything while locked so that we synchronize with relayout. This should be a
+ // very infrequent operation.
+ state = mStateForWindow.get(window);
+ if (state == null) {
+ return;
+ }
+ if (Objects.equals(region, state.mInputRegion)) {
+ return;
+ }
+ state.mInputRegion = region != null ? new Region(region) : null;
+ if (state.mInputChannelToken != null) {
+ try {
+ mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
+ state.mSurfaceControl, state.mParams.flags, state.mInputRegion);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to update surface input channel: ", e);
+ }
+ }
+ }
+ }
+
/**
* IWindowSession implementation.
*/
@@ -211,21 +240,19 @@
}
WindowManager.LayoutParams attrs = state.mParams;
- final Rect surfaceInsets = attrs.surfaceInsets;
- int width = surfaceInsets != null ?
- attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width;
- int height = surfaceInsets != null ?
- attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
-
- t.setBufferSize(sc, width, height)
- .setOpaque(sc, isOpaque(attrs));
if (viewFlags == View.VISIBLE) {
- t.show(sc);
+ final Rect surfaceInsets = attrs.surfaceInsets;
+ int width = surfaceInsets != null
+ ? attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width;
+ int height = surfaceInsets != null
+ ? attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
+
+ t.setBufferSize(sc, width, height).setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+ outSurfaceControl.copyFrom(sc);
} else {
- t.hide(sc);
+ t.hide(sc).apply();
+ outSurfaceControl.release();
}
- t.apply();
- outSurfaceControl.copyFrom(sc);
outFrame.set(0, 0, attrs.width, attrs.height);
mergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
@@ -234,7 +261,7 @@
&& state.mInputChannelToken != null) {
try {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
- attrs.flags);
+ attrs.flags, state.mInputRegion);
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
}
@@ -409,7 +436,7 @@
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags) {
+ int flags, Region region) {
}
@Override
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6646c31..eaaaa80 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -5120,7 +5120,7 @@
* Obtains a pooled instance that is a clone of another one.
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+ * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
* float, float, float)} instead.
*
* @param other The instance to clone.
@@ -5135,7 +5135,7 @@
* Obtains a pooled instance.
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+ * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
* float, float, float)} instead.
*
* @param type The type of the range.
@@ -5271,7 +5271,7 @@
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo} instead.
+ * AccessibilityNodeInfo.CollectionInfo#CollectionInfo} instead.
*
* @param other The instance to clone.
* @hide
@@ -5286,7 +5286,7 @@
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+ * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
* boolean)} instead.
*
* @param rowCount The number of rows, or -1 if count is unknown.
@@ -5303,7 +5303,7 @@
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+ * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
* boolean, int)} instead.
*
* @param rowCount The number of rows.
@@ -5440,7 +5440,7 @@
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo}
+ * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo}
* instead.
*
* @param other The instance to clone.
@@ -5456,7 +5456,7 @@
*
* <p>In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+ * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
* int, int, int, boolean)} instead.
*
* @param rowIndex The row index at which the item is located.
@@ -5476,7 +5476,7 @@
*
* <p>In most situations object pooling is not beneficial. Creates a new instance using the
* constructor {@link
- * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+ * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
* int, int, int, boolean, boolean)} instead.
*
* @param rowIndex The row index at which the item is located.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6d3dbfe..76fe6b5f 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -883,6 +883,25 @@
}
/**
+ * Explicitly cancels the current session and requests a new autofill context.
+ *
+ * <p>Normally, the autofill context is automatically started if necessary when
+ * {@link #notifyViewEntered(View)} is called, but this method should be used in
+ * cases where it must be explicitly started or restarted. Currently, this method should only
+ * be called by
+ * {@link android.service.autofill.augmented.AugmentedAutofillService#requestAutofill(
+ * ComponentName, AutofillId)} to cancel the current session and trigger the autofill flow in
+ * a new session, giving the autofill service or the augmented autofill service a chance to
+ * send updated suggestions.
+ *
+ * @param view view requesting the new autofill context.
+ */
+ void requestAutofillFromNewSession(@NonNull View view) {
+ cancel();
+ notifyViewEntered(view);
+ }
+
+ /**
* Explicitly requests a new autofill context for virtual views.
*
* <p>Normally, the autofill context is automatically started if necessary when
@@ -1403,7 +1422,7 @@
* methods such as {@link android.app.Activity#finish()}.
*/
public void cancel() {
- if (sVerbose) Log.v(TAG, "cancel() called by app");
+ if (sVerbose) Log.v(TAG, "cancel() called by app or augmented autofill service");
if (!hasAutofillFeature()) {
return;
}
@@ -1875,7 +1894,13 @@
final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.addClient(mServiceClient, client.autofillClientGetComponentName(),
userId, receiver);
- final int flags = receiver.getIntResult();
+ int flags = 0;
+ try {
+ flags = receiver.getIntResult();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.w(TAG, "Failed to initialize autofill: " + e);
+ return;
+ }
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
@@ -3484,7 +3509,7 @@
if (sVerbose) {
Log.v(TAG, "requestAutofill() by AugmentedAutofillService.");
}
- afm.post(() -> afm.requestAutofill(view));
+ afm.post(() -> afm.requestAutofillFromNewSession(view));
return true;
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index 6b1a480..4c72474 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -18,11 +18,13 @@
import android.annotation.BinderThread;
import android.annotation.CallbackExecutor;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
-import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -42,26 +44,26 @@
import java.util.function.Consumer;
/**
- * This class represents an inline suggestion which is made by one app
- * and can be embedded into the UI of another. Suggestions may contain
- * sensitive information not known to the host app which needs to be
- * protected from spoofing. To address that the suggestion view inflated
- * on demand for embedding is created in such a way that the hosting app
- * cannot introspect its content and cannot interact with it.
+ * This class represents an inline suggestion which is made by one app and can be embedded into the
+ * UI of another. Suggestions may contain sensitive information not known to the host app which
+ * needs to be protected from spoofing. To address that the suggestion view inflated on demand for
+ * embedding is created in such a way that the hosting app cannot introspect its content and cannot
+ * interact with it.
*/
-@DataClass(
- genEqualsHashCode = true,
- genToString = true,
- genHiddenConstDefs = true,
+@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstDefs = true,
genHiddenConstructor = true)
-@DataClass.Suppress({"getContentProvider"})
public final class InlineSuggestion implements Parcelable {
private static final String TAG = "InlineSuggestion";
- private final @NonNull InlineSuggestionInfo mInfo;
+ @NonNull
+ private final InlineSuggestionInfo mInfo;
- private final @Nullable IInlineContentProvider mContentProvider;
+ /**
+ * @hide
+ */
+ @Nullable
+ private final IInlineContentProvider mContentProvider;
/**
* Used to keep a strong reference to the callback so it doesn't get garbage collected.
@@ -69,7 +71,8 @@
* @hide
*/
@DataClass.ParcelWith(InlineContentCallbackImplParceling.class)
- private @Nullable InlineContentCallbackImpl mInlineContentCallback;
+ @Nullable
+ private InlineContentCallbackImpl mInlineContentCallback;
/**
* Creates a new {@link InlineSuggestion}, for testing purpose.
@@ -87,8 +90,7 @@
*
* @hide
*/
- public InlineSuggestion(
- @NonNull InlineSuggestionInfo info,
+ public InlineSuggestion(@NonNull InlineSuggestionInfo info,
@Nullable IInlineContentProvider contentProvider) {
this(info, contentProvider, /* inlineContentCallback */ null);
}
@@ -96,25 +98,30 @@
/**
* Inflates a view with the content of this suggestion at a specific size.
*
- * <p> The size must be either 1) between the
- * {@link android.widget.inline.InlinePresentationSpec#getMinSize() min size} and the
- * {@link android.widget.inline.InlinePresentationSpec#getMaxSize() max size} of the
- * presentation spec returned by {@link InlineSuggestionInfo#getInlinePresentationSpec()},
- * or 2) {@link ViewGroup.LayoutParams#WRAP_CONTENT}. If the size is set to
- * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, then the size of the inflated view will be just
- * large enough to fit the content, while still conforming to the min / max size specified by
- * the {@link android.widget.inline.InlinePresentationSpec}.
+ * <p> Each dimension of the size must satisfy one of the following conditions:
+ *
+ * <ol>
+ * <li>between {@link android.widget.inline.InlinePresentationSpec#getMinSize()} and
+ * {@link android.widget.inline.InlinePresentationSpec#getMaxSize()} of the presentation spec
+ * from {@code mInfo}
+ * <li>{@link ViewGroup.LayoutParams#WRAP_CONTENT}
+ * </ol>
+ *
+ * If the size is set to {@link
+ * ViewGroup.LayoutParams#WRAP_CONTENT}, then the size of the inflated view will be just large
+ * enough to fit the content, while still conforming to the min / max size specified by the
+ * {@link android.widget.inline.InlinePresentationSpec}.
*
* <p> The caller can attach an {@link android.view.View.OnClickListener} and/or an
- * {@link android.view.View.OnLongClickListener} to the view in the
- * {@code callback} to receive click and long click events on the view.
+ * {@link android.view.View.OnLongClickListener} to the view in the {@code callback} to receive
+ * click and long click events on the view.
*
* @param context Context in which to inflate the view.
- * @param size The size at which to inflate the suggestion. For each dimension, it maybe
- * an exact value or {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
- * @param callback Callback for receiving the inflated view, where the
- * {@link ViewGroup.LayoutParams} of the view is set as the actual size of
- * the underlying remote view.
+ * @param size The size at which to inflate the suggestion. For each dimension, it maybe an
+ * exact value or {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
+ * @param callback Callback for receiving the inflated view, where the {@link
+ * ViewGroup.LayoutParams} of the view is set as the actual size of the
+ * underlying remote view.
* @throws IllegalArgumentException If an invalid argument is passed.
* @throws IllegalStateException If this method is already called.
*/
@@ -130,19 +137,17 @@
+ ", nor wrap_content");
}
mInlineContentCallback = getInlineContentCallback(context, callbackExecutor, callback);
- AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
- if (mContentProvider == null) {
- callback.accept(/* view */ null);
- return;
- }
- try {
- mContentProvider.provideContent(size.getWidth(), size.getHeight(),
- new InlineContentCallbackWrapper(mInlineContentCallback));
- } catch (RemoteException e) {
- Slog.w(TAG, "Error creating suggestion content surface: " + e);
- callback.accept(/* view */ null);
- }
- });
+ if (mContentProvider == null) {
+ callbackExecutor.execute(() -> callback.accept(/* view */ null));
+ return;
+ }
+ try {
+ mContentProvider.provideContent(size.getWidth(), size.getHeight(),
+ new InlineContentCallbackWrapper(mInlineContentCallback));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error creating suggestion content surface: " + e);
+ callbackExecutor.execute(() -> callback.accept(/* view */ null));
+ }
}
/**
@@ -161,9 +166,14 @@
if (mInlineContentCallback != null) {
throw new IllegalStateException("Already called #inflate()");
}
- return new InlineContentCallbackImpl(context, callbackExecutor, callback);
+ return new InlineContentCallbackImpl(context, mContentProvider, callbackExecutor,
+ callback);
}
+ /**
+ * A wrapper class around the {@link InlineContentCallbackImpl} to ensure it's not strongly
+ * reference by the remote system server process.
+ */
private static final class InlineContentCallbackWrapper extends IInlineContentCallback.Stub {
private final WeakReference<InlineContentCallbackImpl> mCallbackImpl;
@@ -201,17 +211,68 @@
}
}
+ /**
+ * Handles the communication between the inline suggestion view in current (IME) process and
+ * the remote view provided from the system server.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single
+ * handler thread to be processed.
+ */
private static final class InlineContentCallbackImpl {
- private final @NonNull Context mContext;
- private final @NonNull Executor mCallbackExecutor;
- private final @NonNull Consumer<InlineContentView> mCallback;
- private @Nullable InlineContentView mView;
+ @NonNull
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ @NonNull
+ private final Context mContext;
+ @Nullable
+ private final IInlineContentProvider mInlineContentProvider;
+ @NonNull
+ private final Executor mCallbackExecutor;
+
+ /**
+ * Callback from the client (IME) that will receive the inflated suggestion view. It'll
+ * only be called once when the view SurfacePackage is first sent back to the client. Any
+ * updates to the view due to attach to window and detach from window events will be
+ * handled under the hood, transparent from the client.
+ */
+ @NonNull
+ private final Consumer<InlineContentView> mCallback;
+
+ /**
+ * Indicates whether the first content has been received or not.
+ */
+ private boolean mFirstContentReceived = false;
+
+ /**
+ * The client (IME) side view which internally wraps a remote view. It'll be set when
+ * {@link #onContent(SurfaceControlViewHost.SurfacePackage, int, int)} is called, which
+ * should only happen once in the lifecycle of this inline suggestion instance.
+ */
+ @Nullable
+ private InlineContentView mView;
+
+ /**
+ * The SurfacePackage pointing to the remote view. It's cached here to be sent to the next
+ * available consumer.
+ */
+ @Nullable
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+
+ /**
+ * The callback (from the {@link InlineContentView}) which consumes the surface package.
+ * It's cached here to be called when the SurfacePackage is returned from the remote
+ * view owning process.
+ */
+ @Nullable
+ private Consumer<SurfaceControlViewHost.SurfacePackage> mSurfacePackageConsumer;
InlineContentCallbackImpl(@NonNull Context context,
+ @Nullable IInlineContentProvider inlineContentProvider,
@NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull Consumer<InlineContentView> callback) {
mContext = context;
+ mInlineContentProvider = inlineContentProvider;
mCallbackExecutor = callbackExecutor;
mCallback = callback;
}
@@ -219,28 +280,110 @@
@BinderThread
public void onContent(SurfaceControlViewHost.SurfacePackage content, int width,
int height) {
- if (content == null) {
+ mMainHandler.post(() -> handleOnContent(content, width, height));
+ }
+
+ @MainThread
+ private void handleOnContent(SurfaceControlViewHost.SurfacePackage content, int width,
+ int height) {
+ if (!mFirstContentReceived) {
+ handleOnFirstContentReceived(content, width, height);
+ mFirstContentReceived = true;
+ } else {
+ handleOnSurfacePackage(content);
+ }
+ }
+
+ /**
+ * Called when the view content is returned for the first time.
+ */
+ @MainThread
+ private void handleOnFirstContentReceived(SurfaceControlViewHost.SurfacePackage content,
+ int width, int height) {
+ mSurfacePackage = content;
+ if (mSurfacePackage == null) {
mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
} else {
mView = new InlineContentView(mContext);
mView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
- mView.setChildSurfacePackage(content);
+ mView.setChildSurfacePackageUpdater(getSurfacePackageUpdater());
mCallbackExecutor.execute(() -> mCallback.accept(mView));
}
}
+ /**
+ * Called when any subsequent SurfacePackage is returned from the remote view owning
+ * process.
+ */
+ @MainThread
+ private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ mSurfacePackage = surfacePackage;
+ if (mSurfacePackage != null && mSurfacePackageConsumer != null) {
+ mSurfacePackageConsumer.accept(mSurfacePackage);
+ mSurfacePackageConsumer = null;
+ }
+ }
+
+ @MainThread
+ private void handleOnSurfacePackageReleased() {
+ mSurfacePackage = null;
+ try {
+ mInlineContentProvider.onSurfacePackageReleased();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
+ }
+ }
+
+ @MainThread
+ private void handleGetSurfacePackage(
+ Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
+ if (mSurfacePackage != null) {
+ consumer.accept(mSurfacePackage);
+ } else {
+ mSurfacePackageConsumer = consumer;
+ try {
+ mInlineContentProvider.requestSurfacePackage();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error calling getSurfacePackage(): " + e);
+ consumer.accept(null);
+ mSurfacePackageConsumer = null;
+ }
+ }
+ }
+
+ private InlineContentView.SurfacePackageUpdater getSurfacePackageUpdater() {
+ return new InlineContentView.SurfacePackageUpdater() {
+ @Override
+ public void onSurfacePackageReleased() {
+ mMainHandler.post(
+ () -> InlineContentCallbackImpl.this.handleOnSurfacePackageReleased());
+ }
+
+ @Override
+ public void getSurfacePackage(
+ Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
+ mMainHandler.post(
+ () -> InlineContentCallbackImpl.this.handleGetSurfacePackage(consumer));
+ }
+ };
+ }
+
@BinderThread
public void onClick() {
- if (mView != null && mView.hasOnClickListeners()) {
- mView.callOnClick();
- }
+ mMainHandler.post(() -> {
+ if (mView != null && mView.hasOnClickListeners()) {
+ mView.callOnClick();
+ }
+ });
}
@BinderThread
public void onLongClick() {
- if (mView != null && mView.hasOnLongClickListeners()) {
- mView.performLongClick();
- }
+ mMainHandler.post(() -> {
+ if (mView != null && mView.hasOnLongClickListeners()) {
+ mView.performLongClick();
+ }
+ });
}
}
@@ -262,6 +405,7 @@
+
// Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
@@ -302,6 +446,14 @@
}
/**
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable IInlineContentProvider getContentProvider() {
+ return mContentProvider;
+ }
+
+ /**
* Used to keep a strong reference to the callback so it doesn't get garbage collected.
*
* @hide
@@ -421,7 +573,7 @@
};
@DataClass.Generated(
- time = 1587771173367L,
+ time = 1588308946517L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nprivate static boolean isValid(int,int,int)\nprivate synchronized android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 4d4faa4..cce1090 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -72,6 +72,9 @@
/**
* The extras state propagated from the IME to pass extra data.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
private @NonNull Bundle mExtras;
@@ -261,6 +264,9 @@
/**
* The extras state propagated from the IME to pass extra data.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
@DataClass.Generated.Member
public @NonNull Bundle getExtras() {
@@ -513,6 +519,9 @@
/**
* The extras state propagated from the IME to pass extra data.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setExtras(@NonNull Bundle value) {
@@ -595,7 +604,7 @@
}
@DataClass.Generated(
- time = 1587537617922L,
+ time = 1588109685838L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3cf6109..71dd665 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -645,6 +645,11 @@
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
synchronized (mH) {
+ if (mCurRootView != null) {
+ // Reset the last served view and restart window focus state of the root view.
+ mCurRootView.getImeFocusController().setServedView(null);
+ mRestartOnNextWindowFocus = true;
+ }
mCurRootView = rootView;
}
}
diff --git a/core/java/android/view/inspector/StaticInspectionCompanionProvider.java b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
index 42a892d..903fc13 100644
--- a/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
+++ b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
@@ -21,8 +21,6 @@
/**
* An inspection companion provider that finds companions as inner classes or generated code.
- *
- * @see android.processor.view.inspector.PlatformInspectableProcessor
*/
public class StaticInspectionCompanionProvider implements InspectionCompanionProvider {
/**
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index e633404..bf0409d 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -206,6 +206,15 @@
return mExtras;
}
+ /** @hide */
+ public Builder toBuilder() {
+ return new Builder(mType)
+ .setTextReply(mTextReply)
+ .setAction(mAction)
+ .setConfidenceScore(mScore)
+ .setExtras(mExtras);
+ }
+
/** Builder class to construct {@link ConversationAction}. */
public static final class Builder {
@Nullable
diff --git a/core/java/android/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
index 4c12dda..b4313b7 100644
--- a/core/java/android/view/textclassifier/EntityConfidence.java
+++ b/core/java/android/view/textclassifier/EntityConfidence.java
@@ -88,6 +88,10 @@
return 0;
}
+ public Map<String, Float> toMap() {
+ return new ArrayMap(mEntityConfidence);
+ }
+
@Override
public String toString() {
return mEntityConfidence.toString();
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 3aed32a..ab6dcb1 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -48,6 +48,7 @@
import java.lang.annotation.RetentionPolicy;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -270,6 +271,20 @@
return mExtras;
}
+ /** @hide */
+ public Builder toBuilder() {
+ return new Builder()
+ .setId(mId)
+ .setText(mText)
+ .addActions(mActions)
+ .setEntityConfidence(mEntityConfidence)
+ .setIcon(mLegacyIcon)
+ .setLabel(mLegacyLabel)
+ .setIntent(mLegacyIntent)
+ .setOnClickListener(mLegacyOnClickListener)
+ .setExtras(mExtras);
+ }
+
@Override
public String toString() {
return String.format(Locale.US,
@@ -323,7 +338,7 @@
*/
public static final class Builder {
- @NonNull private List<RemoteAction> mActions = new ArrayList<>();
+ @NonNull private final List<RemoteAction> mActions = new ArrayList<>();
@NonNull private final Map<String, Float> mTypeScoreMap = new ArrayMap<>();
@Nullable private String mText;
@Nullable private Drawable mLegacyIcon;
@@ -332,8 +347,6 @@
@Nullable private OnClickListener mLegacyOnClickListener;
@Nullable private String mId;
@Nullable private Bundle mExtras;
- @NonNull private final ArrayList<Intent> mActionIntents = new ArrayList<>();
- @Nullable private Bundle mForeignLanguageExtra;
/**
* Sets the classified text.
@@ -361,6 +374,18 @@
return this;
}
+ Builder setEntityConfidence(EntityConfidence scores) {
+ mTypeScoreMap.clear();
+ mTypeScoreMap.putAll(scores.toMap());
+ return this;
+ }
+
+ /** @hide */
+ public Builder clearEntityTypes() {
+ mTypeScoreMap.clear();
+ return this;
+ }
+
/**
* Adds an action that may be performed on the classified text. Actions should be added in
* order of likelihood that the user will use them, with the most likely action being added
@@ -368,19 +393,21 @@
*/
@NonNull
public Builder addAction(@NonNull RemoteAction action) {
- return addAction(action, null);
- }
-
- /**
- * @param intent the intent in the remote action.
- * @see #addAction(RemoteAction)
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public Builder addAction(RemoteAction action, @Nullable Intent intent) {
Preconditions.checkArgument(action != null);
mActions.add(action);
- mActionIntents.add(intent);
+ return this;
+ }
+
+ /** @hide */
+ public Builder addActions(Collection<RemoteAction> actions) {
+ Objects.requireNonNull(actions);
+ mActions.addAll(actions);
+ return this;
+ }
+
+ /** @hide */
+ public Builder clearActions() {
+ mActions.clear();
return this;
}
@@ -466,16 +493,6 @@
}
/**
- * @see #setExtras(Bundle)
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public Builder setForeignLanguageExtra(@Nullable Bundle extra) {
- mForeignLanguageExtra = extra;
- return this;
- }
-
- /**
* Builds and returns a {@link TextClassification} object.
*/
@NonNull
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index fb96210..b35eb06 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -714,9 +714,7 @@
/**
* Callback object to be called when the toast is shown or hidden.
*
- * <p>Callback methods will be called on the looper thread used for the {@link Toast} object.
- *
- * @see #makeText(Context, Looper, CharSequence, int)
+ * @see #makeText(Context, CharSequence, int)
* @see #addCallback(Callback)
*/
public abstract static class Callback {
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 4f2af63..8657e82 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -21,40 +21,45 @@
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
+import java.util.function.Consumer;
+
/**
- * This class represents a view that holds opaque content from another app that
- * you can inline in your UI.
+ * This class represents a view that holds opaque content from another app that you can inline in
+ * your UI.
*
* <p>Since the content presented by this view is from another security domain,it is
- * shown on a remote surface preventing the host application from accessing that content.
- * Also the host application cannot interact with the inlined content by injecting touch
- * events or clicking programmatically.
+ * shown on a remote surface preventing the host application from accessing that content. Also the
+ * host application cannot interact with the inlined content by injecting touch events or clicking
+ * programmatically.
*
* <p>This view can be overlaid by other windows, i.e. redressed, but if this is the case
- * the inined UI would not be interactive. Sometimes this is desirable, e.g. animating
- * transitions.
+ * the inlined UI would not be interactive. Sometimes this is desirable, e.g. animating transitions.
*
* <p>By default the surface backing this view is shown on top of the hosting window such
- * that the inlined content is interactive. However, you can temporarily move the surface
- * under the hosting window which could be useful in some cases, e.g. animating transitions.
- * At this point the inlined content will not be interactive and the touch events would
- * be delivered to your app.
- * <p>
- * Instances of this class are created by the platform and can be programmatically attached
- * to your UI. Once you attach and detach this view it can not longer be reused and you
- * should obtain a new view from the platform via the dedicated APIs.
+ * that the inlined content is interactive. However, you can temporarily move the surface under the
+ * hosting window which could be useful in some cases, e.g. animating transitions. At this point the
+ * inlined content will not be interactive and the touch events would be delivered to your app.
+ *
+ * <p> Instances of this class are created by the platform and can be programmatically attached to
+ * your UI. Once the view is attached to the window, you may detach and reattach it to the window.
+ * It should work seamlessly from the hosting process's point of view.
*/
public class InlineContentView extends ViewGroup {
+ private static final String TAG = "InlineContentView";
+
+ private static final boolean DEBUG = false;
+
/**
- * Callback for observing the lifecycle of the surface control
- * that manipulates the backing secure embedded UI surface.
+ * Callback for observing the lifecycle of the surface control that manipulates the backing
+ * secure embedded UI surface.
*/
public interface SurfaceControlCallback {
/**
@@ -72,15 +77,41 @@
void onDestroyed(@NonNull SurfaceControl surfaceControl);
}
- private final @NonNull SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
+ /**
+ * Callback for sending an updated surface package in case the previous one is released
+ * from the detached from window event, and for getting notified of such event.
+ *
+ * This is expected to be provided to the {@link InlineContentView} so it can get updates
+ * from and send updates to the remote content (i.e. surface package) provider.
+ *
+ * @hide
+ */
+ public interface SurfacePackageUpdater {
+
+ /**
+ * Called when the previous surface package is released due to view being detached
+ * from the window.
+ */
+ void onSurfacePackageReleased();
+
+ /**
+ * Called to request an updated surface package.
+ *
+ * @param consumer consumes the updated surface package.
+ */
+ void getSurfacePackage(Consumer<SurfaceControlViewHost.SurfacePackage> consumer);
+ }
+
+ @NonNull
+ private final SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
mSurfaceControlCallback.onCreated(mSurfaceView.getSurfaceControl());
}
@Override
- public void surfaceChanged(@NonNull SurfaceHolder holder,
- int format, int width, int height) {
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
/* do nothing */
}
@@ -90,13 +121,17 @@
}
};
- private final @NonNull SurfaceView mSurfaceView;
+ @NonNull
+ private final SurfaceView mSurfaceView;
- private @Nullable SurfaceControlCallback mSurfaceControlCallback;
+ @Nullable
+ private SurfaceControlCallback mSurfaceControlCallback;
+
+ @Nullable
+ private SurfacePackageUpdater mSurfacePackageUpdater;
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context) {
@@ -105,7 +140,6 @@
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -114,7 +148,6 @@
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
@@ -123,20 +156,18 @@
}
/**
- * Gets the surface control. If the surface is not created this method
- * returns {@code null}.
+ * Gets the surface control. If the surface is not created this method returns {@code null}.
*
* @return The surface control.
- *
* @see #setSurfaceControlCallback(SurfaceControlCallback)
*/
- public @Nullable SurfaceControl getSurfaceControl() {
+ @Nullable
+ public SurfaceControl getSurfaceControl() {
return mSurfaceView.getSurfaceControl();
}
/**
* @inheritDoc
- *
* @hide
*/
public InlineContentView(@NonNull Context context, @Nullable AttributeSet attrs,
@@ -149,14 +180,35 @@
}
/**
- * Sets the embedded UI.
- * @param surfacePackage The embedded UI.
+ * Sets the embedded UI provider.
*
* @hide
*/
- public void setChildSurfacePackage(
- @Nullable SurfaceControlViewHost.SurfacePackage surfacePackage) {
- mSurfaceView.setChildSurfacePackage(surfacePackage);
+ public void setChildSurfacePackageUpdater(
+ @Nullable SurfacePackageUpdater surfacePackageUpdater) {
+ mSurfacePackageUpdater = surfacePackageUpdater;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ if (DEBUG) Log.v(TAG, "onAttachedToWindow");
+ super.onAttachedToWindow();
+ if (mSurfacePackageUpdater != null) {
+ mSurfacePackageUpdater.getSurfacePackage(
+ sp -> {
+ if (DEBUG) Log.v(TAG, "Received new SurfacePackage");
+ mSurfaceView.setChildSurfacePackage(sp);
+ });
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (DEBUG) Log.v(TAG, "onDetachedFromWindow");
+ super.onDetachedFromWindow();
+ if (mSurfacePackageUpdater != null) {
+ mSurfacePackageUpdater.onSurfacePackageReleased();
+ }
}
@Override
@@ -165,8 +217,8 @@
}
/**
- * Sets a callback to observe the lifecycle of the surface control for
- * managing the backing surface.
+ * Sets a callback to observe the lifecycle of the surface control for managing the backing
+ * surface.
*
* @param callback The callback to set or {@code null} to clear.
*/
@@ -182,7 +234,6 @@
/**
* @return Whether the surface backing this view appears on top of its parent.
- *
* @see #setZOrderedOnTop(boolean)
*/
public boolean isZOrderedOnTop() {
@@ -190,17 +241,15 @@
}
/**
- * Controls whether the backing surface is placed on top of this view's window.
- * Normally, it is placed on top of the window, to allow interaction
- * with the inlined UI. Via this method, you can place the surface below the
- * window. This means that all of the contents of the window this view is in
- * will be visible on top of its surface.
+ * Controls whether the backing surface is placed on top of this view's window. Normally, it is
+ * placed on top of the window, to allow interaction with the inlined UI. Via this method, you
+ * can place the surface below the window. This means that all of the contents of the window
+ * this view is in will be visible on top of its surface.
*
* <p> The Z ordering can be changed dynamically if the backing surface is
* created, otherwise the ordering would be applied at surface construction time.
*
* @param onTop Whether to show the surface on top of this view's window.
- *
* @see #isZOrderedOnTop()
*/
public boolean setZOrderedOnTop(boolean onTop) {
diff --git a/core/java/android/widget/inline/InlinePresentationSpec.java b/core/java/android/widget/inline/InlinePresentationSpec.java
index 9f966d8..5f924c6 100644
--- a/core/java/android/widget/inline/InlinePresentationSpec.java
+++ b/core/java/android/widget/inline/InlinePresentationSpec.java
@@ -44,6 +44,9 @@
/**
* The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case
* the default system UI style will be used.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
@NonNull
private final Bundle mStyle;
@@ -122,6 +125,9 @@
/**
* The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case
* the default system UI style will be used.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
@DataClass.Generated.Member
public @NonNull Bundle getStyle() {
@@ -260,6 +266,9 @@
/**
* The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case
* the default system UI style will be used.
+ *
+ * <p>Note: There should be no remote objects in the bundle, all included remote objects will
+ * be removed from the bundle before transmission.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setStyle(@NonNull Bundle value) {
@@ -293,7 +302,7 @@
}
@DataClass.Generated(
- time = 1586935491105L,
+ time = 1588109681295L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/widget/inline/InlinePresentationSpec.java",
inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.NonNull android.os.Bundle mStyle\nprivate static @android.annotation.NonNull android.os.Bundle defaultStyle()\nprivate boolean styleEquals(android.os.Bundle)\npublic void filterContentTypes()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/window/TaskEmbedder.java b/core/java/android/window/TaskEmbedder.java
index 2ead37a..ca6c568 100644
--- a/core/java/android/window/TaskEmbedder.java
+++ b/core/java/android/window/TaskEmbedder.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
-import android.app.ActivityView;
import android.app.IActivityTaskManager;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -36,13 +35,15 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.VirtualDisplay;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
import android.view.IWindow;
import android.view.IWindowManager;
+import android.view.IWindowSession;
import android.view.KeyEvent;
import android.view.SurfaceControl;
+import android.view.WindowManagerGlobal;
import dalvik.system.CloseGuard;
@@ -186,31 +187,45 @@
/**
* Called when the task embedder should be initialized.
+ * NOTE: all overriding methods should call this one after they finish their initialization.
* @return whether to report whether the embedder was initialized.
*/
- public abstract boolean onInitialize();
+ public boolean onInitialize() {
+ updateLocationAndTapExcludeRegion();
+ return true;
+ }
/**
* Called when the task embedder should be released.
* @return whether to report whether the embedder was released.
*/
- protected abstract boolean onRelease();
+ protected boolean onRelease() {
+ // Clear tap-exclude region (if any) for this window.
+ clearTapExcludeRegion();
+ return true;
+ }
/**
* Starts presentation of tasks in this container.
*/
- public abstract void start();
+ public void start() {
+ updateLocationAndTapExcludeRegion();
+ }
/**
* Stops presentation of tasks in this container.
*/
- public abstract void stop();
+ public void stop() {
+ clearTapExcludeRegion();
+ }
/**
* This should be called whenever the position or size of the surface changes
* or if touchable areas above the surface are added or removed.
*/
- public abstract void notifyBoundsChanged();
+ public void notifyBoundsChanged() {
+ updateLocationAndTapExcludeRegion();
+ }
/**
* Called to update the dimensions whenever the host size changes.
@@ -256,6 +271,10 @@
return INVALID_DISPLAY;
}
+ public VirtualDisplay getVirtualDisplay() {
+ return null;
+ }
+
/**
* Set forwarded insets on the task content.
*
@@ -266,6 +285,48 @@
}
/**
+ * Updates position and bounds information needed by WM and IME to manage window
+ * focus and touch events properly.
+ * <p>
+ * This should be called whenever the position or size of the surface changes
+ * or if touchable areas above the surface are added or removed.
+ */
+ protected void updateLocationAndTapExcludeRegion() {
+ if (!isInitialized() || mHost.getWindow() == null) {
+ return;
+ }
+ applyTapExcludeRegion(mHost.getWindow(), mHost.getTapExcludeRegion());
+ }
+
+ /**
+ * Call to update the tap exclude region for the window.
+ * <p>
+ * This should not normally be called directly, but through
+ * {@link #updateLocationAndTapExcludeRegion()}. This method
+ * is provided as an optimization when managing multiple TaskSurfaces within a view.
+ *
+ * @see IWindowSession#updateTapExcludeRegion(IWindow, Region)
+ */
+ private void applyTapExcludeRegion(IWindow window, @Nullable Region tapExcludeRegion) {
+ try {
+ IWindowSession session = WindowManagerGlobal.getWindowSession();
+ session.updateTapExcludeRegion(window, tapExcludeRegion);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Removes the tap exclude region set by {@link #updateLocationAndTapExcludeRegion()}.
+ */
+ private void clearTapExcludeRegion() {
+ if (!isInitialized() || mHost.getWindow() == null) {
+ return;
+ }
+ applyTapExcludeRegion(mHost.getWindow(), null);
+ }
+
+ /**
* Set the callback to be notified about state changes.
* <p>This class must finish initializing before {@link #startActivity(Intent)} can be called.
* <p>Note: If the instance was ready prior to this call being made, then
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 2fb4650..1b87521 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -75,7 +75,8 @@
// infrastructure is ready.
mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
- return true;
+
+ return super.onInitialize();
}
@Override
@@ -96,6 +97,7 @@
*/
@Override
public void start() {
+ super.start();
if (DEBUG) {
log("start");
}
@@ -119,6 +121,7 @@
*/
@Override
public void stop() {
+ super.stop();
if (DEBUG) {
log("stop");
}
@@ -143,6 +146,7 @@
*/
@Override
public void notifyBoundsChanged() {
+ super.notifyBoundsChanged();
if (DEBUG) {
log("notifyBoundsChanged: screenBounds=" + mHost.getScreenBounds());
}
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index 1c0598b..2e6cbee 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -21,7 +21,6 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
import static android.view.Display.INVALID_DISPLAY;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -40,7 +39,6 @@
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.IWindow;
import android.view.IWindowManager;
import android.view.IWindowSession;
import android.view.InputDevice;
@@ -134,20 +132,15 @@
e.rethrowAsRuntimeException();
}
- if (mHost.getWindow() != null) {
- updateLocationAndTapExcludeRegion();
- }
- return true;
+ return super.onInitialize();
}
@Override
protected boolean onRelease() {
+ super.onRelease();
// Clear activity view geometry for IME on this display
clearActivityViewGeometryForIme();
- // Clear tap-exclude region (if any) for this window.
- clearTapExcludeRegion();
-
if (mTaskStackListener != null) {
try {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
@@ -170,9 +163,9 @@
*/
@Override
public void start() {
+ super.start();
if (isInitialized()) {
mVirtualDisplay.setDisplayState(true);
- updateLocationAndTapExcludeRegion();
}
}
@@ -181,23 +174,14 @@
*/
@Override
public void stop() {
+ super.stop();
if (isInitialized()) {
mVirtualDisplay.setDisplayState(false);
clearActivityViewGeometryForIme();
- clearTapExcludeRegion();
}
}
/**
- * This should be called whenever the position or size of the surface changes
- * or if touchable areas above the surface are added or removed.
- */
- @Override
- public void notifyBoundsChanged() {
- updateLocationAndTapExcludeRegion();
- }
-
- /**
* Called to update the dimensions whenever the host size changes.
*
* @param width the new width of the surface
@@ -251,6 +235,14 @@
return INVALID_DISPLAY;
}
+ @Override
+ public VirtualDisplay getVirtualDisplay() {
+ if (isInitialized()) {
+ return mVirtualDisplay;
+ }
+ return null;
+ }
+
/**
* Check if container is ready to launch and create {@link ActivityOptions} to target the
* virtual display.
@@ -290,12 +282,13 @@
* This should be called whenever the position or size of the surface changes
* or if touchable areas above the surface are added or removed.
*/
- private void updateLocationAndTapExcludeRegion() {
+ @Override
+ protected void updateLocationAndTapExcludeRegion() {
+ super.updateLocationAndTapExcludeRegion();
if (!isInitialized() || mHost.getWindow() == null) {
return;
}
reportLocation(mHost.getScreenToTaskMatrix(), mHost.getPositionInWindow());
- applyTapExcludeRegion(mHost.getWindow(), mHost.getTapExcludeRegion());
}
/**
@@ -324,24 +317,6 @@
}
/**
- * Call to update the tap exclude region for the window.
- * <p>
- * This should not normally be called directly, but through
- * {@link #updateLocationAndTapExcludeRegion()}. This method
- * is provided as an optimization when managing multiple TaskSurfaces within a view.
- *
- * @see IWindowSession#updateTapExcludeRegion(IWindow, Region)
- */
- private void applyTapExcludeRegion(IWindow window, @Nullable Region tapExcludeRegion) {
- try {
- IWindowSession session = WindowManagerGlobal.getWindowSession();
- session.updateTapExcludeRegion(window, tapExcludeRegion);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- }
-
- /**
* @see InputMethodManager#reportActivityView(int, Matrix)
*/
private void clearActivityViewGeometryForIme() {
@@ -349,17 +324,6 @@
mContext.getSystemService(InputMethodManager.class).reportActivityView(displayId, null);
}
- /**
- * Removes the tap exclude region set by {@link #updateLocationAndTapExcludeRegion()}.
- */
- private void clearTapExcludeRegion() {
- if (mHost.getWindow() == null) {
- Log.w(TAG, "clearTapExcludeRegion: not attached to window!");
- return;
- }
- applyTapExcludeRegion(mHost.getWindow(), null);
- }
-
private static KeyEvent createKeyEvent(int action, int code, int displayId) {
long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index e0bbc04..28c9464 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -43,7 +43,7 @@
public abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {
private static final int NUM_OF_TOP_ANNOTATIONS_TO_USE = 3;
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final String TAG = "AbstractResolverComp";
protected AfterCompute mAfterCompute;
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index 986614c..37a5a63 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -28,9 +28,11 @@
import android.content.pm.ResolveInfo;
import android.os.Message;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.util.Log;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import java.util.ArrayList;
import java.util.HashMap;
@@ -48,7 +50,6 @@
class AppPredictionServiceResolverComparator extends AbstractResolverComparator {
private static final String TAG = "APSResolverComparator";
- private static final boolean DEBUG = false;
private final AppPredictor mAppPredictor;
private final Context mContext;
@@ -61,6 +62,11 @@
// back to using the ResolverRankerService.
private ResolverRankerServiceResolverComparator mResolverRankerService;
+ private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
+ true);
+
AppPredictionServiceResolverComparator(
Context context,
Intent intent,
@@ -113,9 +119,7 @@
mAppPredictor.sortTargets(appTargets, Executors.newSingleThreadExecutor(),
sortedAppTargets -> {
if (sortedAppTargets.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG, "AppPredictionService disabled. Using resolver.");
- }
+ Log.i(TAG, "AppPredictionService disabled. Using resolver.");
// APS for chooser is disabled. Fallback to resolver.
mResolverRankerService =
new ResolverRankerServiceResolverComparator(
@@ -123,9 +127,7 @@
() -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT));
mResolverRankerService.compute(targets);
} else {
- if (DEBUG) {
- Log.d(TAG, "AppPredictionService response received");
- }
+ Log.i(TAG, "AppPredictionService response received");
Message msg =
Message.obtain(mHandler, RANKER_SERVICE_RESULT, sortedAppTargets);
msg.sendToTarget();
@@ -145,8 +147,11 @@
target.getRank()));
}
for (int i = 0; i < sortedAppTargets.size(); i++) {
- mTargetRanks.put(new ComponentName(sortedAppTargets.get(i).getPackageName(),
- sortedAppTargets.get(i).getClassName()), i);
+ ComponentName componentName = new ComponentName(
+ sortedAppTargets.get(i).getPackageName(),
+ sortedAppTargets.get(i).getClassName());
+ mTargetRanks.put(componentName, i);
+ Log.i(TAG, "handleResultMessage, sortedAppTargets #" + i + ": " + componentName);
}
} else if (msg.obj == null && mResolverRankerService == null) {
Log.e(TAG, "Unexpected null result");
@@ -167,7 +172,7 @@
if (mResolverRankerService != null) {
return mResolverRankerService.getScore(name);
}
- if (!mTargetScores.isEmpty()) {
+ if (mAppendDirectShareEnabled && !mTargetScores.isEmpty()) {
return mTargetScores.get(name);
}
Integer rank = mTargetRanks.get(name);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a144ffb..3fc3f3e 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -33,6 +33,7 @@
import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -157,6 +158,7 @@
private static final String TAG = "ChooserActivity";
private AppPredictor mPersonalAppPredictor;
private AppPredictor mWorkAppPredictor;
+ private boolean mShouldDisplayLandscape;
@UnsupportedAppUsage
public ChooserActivity() {
@@ -191,6 +193,8 @@
// TODO(b/123088566) Share these in a better way.
private static final String APP_PREDICTION_SHARE_UI_SURFACE = "share";
public static final String LAUNCH_LOCATION_DIRECT_SHARE = "direct_share";
+ public static final String CHOOSER_TARGET = "chooser_target";
+ private static final String SHORTCUT_TARGET = "shortcut_target";
private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
@@ -247,6 +251,10 @@
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
true);
+ private boolean mChooserTargetRankingEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.CHOOSER_TARGET_RANKING_ENABLED,
+ true);
private Bundle mReplacementExtras;
private IntentSender mChosenComponentSender;
@@ -430,6 +438,7 @@
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 4;
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5;
private static final int LIST_VIEW_UPDATE_MESSAGE = 6;
+ private static final int CHOOSER_TARGET_RANKING_SCORE = 7;
private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000;
private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000;
@@ -448,6 +457,7 @@
removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT);
removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED);
+ removeMessages(CHOOSER_TARGET_RANKING_SCORE);
}
private void restartServiceRequestTimer() {
@@ -559,6 +569,17 @@
getChooserActivityLogger().logSharesheetDirectLoadComplete();
break;
+ case CHOOSER_TARGET_RANKING_SCORE:
+ if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_RANKING_SCORE");
+ final ChooserTargetRankingInfo scoreInfo = (ChooserTargetRankingInfo) msg.obj;
+ ChooserListAdapter adapterForUserHandle =
+ mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle(
+ scoreInfo.userHandle);
+ if (adapterForUserHandle != null) {
+ adapterForUserHandle.addChooserTargetRankingScore(scoreInfo.scores);
+ }
+ break;
+
default:
super.handleMessage(msg);
}
@@ -696,6 +717,8 @@
mCallerChooserTargets = targets;
}
+ mShouldDisplayLandscape = shouldDisplayLandscape(
+ getResources().getConfiguration().orientation);
setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
@@ -787,10 +810,26 @@
getDisplayResolveInfos(chooserListAdapter);
final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
new ArrayList<>();
+
+ // Separate ChooserTargets ranking scores and ranked Shortcuts.
+ List<AppTarget> shortcutResults = new ArrayList<>();
+ List<AppTarget> chooserTargetScores = new ArrayList<>();
for (AppTarget appTarget : resultList) {
if (appTarget.getShortcutInfo() == null) {
continue;
}
+ if (appTarget.getShortcutInfo().getId().equals(CHOOSER_TARGET)) {
+ chooserTargetScores.add(appTarget);
+ } else {
+ shortcutResults.add(appTarget);
+ }
+ }
+ resultList = shortcutResults;
+ if (mChooserTargetRankingEnabled) {
+ sendChooserTargetRankingScore(chooserTargetScores,
+ chooserListAdapter.getUserHandle());
+ }
+ for (AppTarget appTarget : resultList) {
shareShortcutInfos.add(new ShortcutManager.ShareShortcutInfo(
appTarget.getShortcutInfo(),
new ComponentName(
@@ -848,7 +887,8 @@
/* context */ this,
adapter,
getPersonalProfileUserHandle(),
- /* workProfileUserHandle= */ null);
+ /* workProfileUserHandle= */ null,
+ isSendAction(getTargetIntent()));
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
@@ -878,7 +918,8 @@
workAdapter,
selectedProfile,
getPersonalProfileUserHandle(),
- getWorkProfileUserHandle());
+ getWorkProfileUserHandle(),
+ isSendAction(getTargetIntent()));
}
private int findSelectedProfile() {
@@ -1035,6 +1076,7 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation);
adjustPreviewWidth(newConfig.orientation, null);
updateStickyContentPreview();
}
@@ -1048,7 +1090,7 @@
private void adjustPreviewWidth(int orientation, View parent) {
int width = -1;
- if (shouldDisplayLandscape(orientation)) {
+ if (mShouldDisplayLandscape) {
width = getResources().getDimensionPixelSize(R.dimen.chooser_preview_width);
}
@@ -1973,6 +2015,14 @@
});
}
+ private void sendChooserTargetRankingScore(List<AppTarget> chooserTargetScores,
+ UserHandle userHandle) {
+ final Message msg = Message.obtain();
+ msg.what = ChooserHandler.CHOOSER_TARGET_RANKING_SCORE;
+ msg.obj = new ChooserTargetRankingInfo(chooserTargetScores, userHandle);
+ mChooserHandler.sendMessage(msg);
+ }
+
private void sendShareShortcutInfoList(
List<ShortcutManager.ShareShortcutInfo> resultList,
List<DisplayResolveInfo> driList,
@@ -2170,6 +2220,7 @@
ChooserListAdapter currentListAdapter =
mChooserMultiProfilePagerAdapter.getActiveListAdapter();
if (currentListAdapter != null) {
+ sendImpressionToAppPredictor(info, currentListAdapter);
currentListAdapter.updateModel(info.getResolvedComponentName());
currentListAdapter.updateChooserCounts(ri.activityInfo.packageName,
targetIntent.getAction());
@@ -2185,6 +2236,37 @@
mIsSuccessfullySelected = true;
}
+ private void sendImpressionToAppPredictor(TargetInfo targetInfo, ChooserListAdapter adapter) {
+ if (!mChooserTargetRankingEnabled) {
+ return;
+ }
+ AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled(
+ mChooserMultiProfilePagerAdapter.getCurrentUserHandle());
+ if (directShareAppPredictor == null) {
+ return;
+ }
+ // Send DS target impression info to AppPredictor, only when user chooses app share.
+ if (targetInfo instanceof ChooserTargetInfo) {
+ return;
+ }
+ List<ChooserTargetInfo> surfacedTargetInfo = adapter.getSurfacedTargetInfo();
+ List<AppTargetId> targetIds = new ArrayList<>();
+ for (ChooserTargetInfo chooserTargetInfo : surfacedTargetInfo) {
+ ChooserTarget chooserTarget = chooserTargetInfo.getChooserTarget();
+ String componentName = chooserTarget.getComponentName().flattenToString();
+ if (mDirectShareShortcutInfoCache.containsKey(chooserTarget)) {
+ String shortcutId = mDirectShareShortcutInfoCache.get(chooserTarget).getId();
+ targetIds.add(new AppTargetId(
+ String.format("%s/%s/%s", shortcutId, componentName, SHORTCUT_TARGET)));
+ } else {
+ String titleHash = ChooserUtil.md5(chooserTarget.getTitle().toString());
+ targetIds.add(new AppTargetId(
+ String.format("%s/%s/%s", titleHash, componentName, CHOOSER_TARGET)));
+ }
+ }
+ directShareAppPredictor.notifyLaunchLocationShown(LAUNCH_LOCATION_DIRECT_SHARE, targetIds);
+ }
+
private void sendClickToAppPredictor(TargetInfo targetInfo) {
AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled(
mChooserMultiProfilePagerAdapter.getCurrentUserHandle());
@@ -2199,6 +2281,28 @@
if (mDirectShareAppTargetCache != null) {
appTarget = mDirectShareAppTargetCache.get(chooserTarget);
}
+ if (mChooserTargetRankingEnabled && appTarget == null) {
+ // Send ChooserTarget sharing info to AppPredictor.
+ ComponentName componentName = chooserTarget.getComponentName();
+ try {
+ appTarget = new AppTarget.Builder(
+ new AppTargetId(componentName.flattenToString()),
+ new ShortcutInfo.Builder(
+ createPackageContextAsUser(
+ componentName.getPackageName(),
+ 0 /* flags */,
+ getUser()),
+ CHOOSER_TARGET)
+ .setActivity(componentName)
+ .setShortLabel(ChooserUtil.md5(chooserTarget.getTitle().toString()))
+ .build())
+ .setClassName(componentName.getClassName())
+ .build();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not look up service " + componentName
+ + "; component name not found");
+ }
+ }
// This is a direct share click that was provided by the APS
if (appTarget != null) {
directShareAppPredictor.notifyAppTargetEvent(
@@ -2840,6 +2944,19 @@
.setSubtype(previewType));
}
+ class ViewHolderBase extends RecyclerView.ViewHolder {
+ private int mViewType;
+
+ ViewHolderBase(View itemView, int viewType) {
+ super(itemView);
+ this.mViewType = viewType;
+ }
+
+ int getViewType() {
+ return mViewType;
+ }
+ }
+
/**
* Used to bind types of individual item including
* {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
@@ -2847,12 +2964,12 @@
* {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
* and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
*/
- final class ItemViewHolder extends RecyclerView.ViewHolder {
+ final class ItemViewHolder extends ViewHolderBase {
ResolverListAdapter.ViewHolder mWrappedViewHolder;
int mListPosition = ChooserListAdapter.NO_POSITION;
- ItemViewHolder(View itemView, boolean isClickable) {
- super(itemView);
+ ItemViewHolder(View itemView, boolean isClickable, int viewType) {
+ super(itemView, viewType);
mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);
if (isClickable) {
itemView.setOnClickListener(v -> startSelected(mListPosition,
@@ -2870,9 +2987,9 @@
/**
* Add a footer to the list, to support scrolling behavior below the navbar.
*/
- final class FooterViewHolder extends RecyclerView.ViewHolder {
- FooterViewHolder(View itemView) {
- super(itemView);
+ final class FooterViewHolder extends ViewHolderBase {
+ FooterViewHolder(View itemView, int viewType) {
+ super(itemView, viewType);
}
}
@@ -2983,7 +3100,7 @@
int getMaxTargetsPerRow() {
int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
- if (shouldDisplayLandscape(getResources().getConfiguration().orientation)) {
+ if (mShouldDisplayLandscape) {
maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
}
return maxTargets;
@@ -3091,13 +3208,14 @@
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_CONTENT_PREVIEW:
- return new ItemViewHolder(createContentPreviewView(parent), false);
+ return new ItemViewHolder(createContentPreviewView(parent), false, viewType);
case VIEW_TYPE_PROFILE:
- return new ItemViewHolder(createProfileView(parent), false);
+ return new ItemViewHolder(createProfileView(parent), false, viewType);
case VIEW_TYPE_AZ_LABEL:
- return new ItemViewHolder(createAzLabelView(parent), false);
+ return new ItemViewHolder(createAzLabelView(parent), false, viewType);
case VIEW_TYPE_NORMAL:
- return new ItemViewHolder(mChooserListAdapter.createView(parent), true);
+ return new ItemViewHolder(
+ mChooserListAdapter.createView(parent), true, viewType);
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
return createItemGroupViewHolder(viewType, parent);
@@ -3105,7 +3223,7 @@
Space sp = new Space(parent.getContext());
sp.setLayoutParams(new RecyclerView.LayoutParams(
LayoutParams.MATCH_PARENT, mFooterHeight));
- return new FooterViewHolder(sp);
+ return new FooterViewHolder(sp, viewType);
default:
// Since we catch all possible viewTypes above, no chance this is being called.
return null;
@@ -3114,7 +3232,7 @@
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- int viewType = getItemViewType(position);
+ int viewType = ((ViewHolderBase) holder).getViewType();
switch (viewType) {
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
@@ -3225,7 +3343,6 @@
}
viewGroup.setTag(holder);
-
return holder;
}
@@ -3252,14 +3369,15 @@
parentGroup.addView(row2);
mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
- Lists.newArrayList(row1, row2), getMaxTargetsPerRow());
+ Lists.newArrayList(row1, row2), getMaxTargetsPerRow(), viewType);
loadViewsIntoGroup(mDirectShareViewHolder);
return mDirectShareViewHolder;
} else {
ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
false);
- ItemGroupViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
+ ItemGroupViewHolder holder =
+ new SingleRowViewHolder(row, getMaxTargetsPerRow(), viewType);
loadViewsIntoGroup(holder);
return holder;
@@ -3421,14 +3539,14 @@
* {@link ChooserGridAdapter#VIEW_TYPE_DIRECT_SHARE},
* and {@link ChooserGridAdapter#VIEW_TYPE_CALLER_AND_RANK}.
*/
- abstract class ItemGroupViewHolder extends RecyclerView.ViewHolder {
+ abstract class ItemGroupViewHolder extends ViewHolderBase {
protected int mMeasuredRowHeight;
private int[] mItemIndices;
protected final View[] mCells;
private final int mColumnCount;
- ItemGroupViewHolder(int cellCount, View itemView) {
- super(itemView);
+ ItemGroupViewHolder(int cellCount, View itemView, int viewType) {
+ super(itemView, viewType);
this.mCells = new View[cellCount];
this.mItemIndices = new int[cellCount];
this.mColumnCount = cellCount;
@@ -3474,8 +3592,8 @@
class SingleRowViewHolder extends ItemGroupViewHolder {
private final ViewGroup mRow;
- SingleRowViewHolder(ViewGroup row, int cellCount) {
- super(cellCount, row);
+ SingleRowViewHolder(ViewGroup row, int cellCount, int viewType) {
+ super(cellCount, row, viewType);
this.mRow = row;
}
@@ -3517,8 +3635,9 @@
private final boolean[] mCellVisibility;
- DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
- super(rows.size() * cellCountPerRow, parent);
+ DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow,
+ int viewType) {
+ super(rows.size() * cellCountPerRow, parent, viewType);
this.mParent = parent;
this.mRows = rows;
@@ -3772,6 +3891,17 @@
}
}
+ static class ChooserTargetRankingInfo {
+ public final List<AppTarget> scores;
+ public final UserHandle userHandle;
+
+ ChooserTargetRankingInfo(List<AppTarget> chooserTargetScores,
+ UserHandle userHandle) {
+ this.scores = chooserTargetScores;
+ this.userHandle = userHandle;
+ }
+ }
+
static class RefinementResultReceiver extends ResultReceiver {
private ChooserActivity mChooserActivity;
private TargetInfo mSelectedTarget;
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
new file mode 100644
index 0000000..317a987
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.internal.widget.GridLayoutManager;
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * For a11y and per {@link RecyclerView#onInitializeAccessibilityNodeInfo}, override
+ * methods to ensure proper row counts.
+ */
+public class ChooserGridLayoutManager extends GridLayoutManager {
+
+ /**
+ * Constructor used when layout manager is set in XML by RecyclerView attribute
+ * "layoutManager". If spanCount is not specified in the XML, it defaults to a
+ * single column.
+ *
+ */
+ public ChooserGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /**
+ * Creates a vertical GridLayoutManager
+ *
+ * @param context Current context, will be used to access resources.
+ * @param spanCount The number of columns in the grid
+ */
+ public ChooserGridLayoutManager(Context context, int spanCount) {
+ super(context, spanCount);
+ }
+
+ /**
+ * @param context Current context, will be used to access resources.
+ * @param spanCount The number of columns or rows in the grid
+ * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link
+ * #VERTICAL}.
+ * @param reverseLayout When set to true, layouts from end to start.
+ */
+ public ChooserGridLayoutManager(Context context, int spanCount, int orientation,
+ boolean reverseLayout) {
+ super(context, spanCount, orientation, reverseLayout);
+ }
+
+ @Override
+ public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ // Do not count the footer view in the official count
+ return super.getRowCountForAccessibility(recycler, state) - 1;
+ }
+}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 73ee295..f426bc0 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -21,6 +21,7 @@
import android.app.ActivityManager;
import android.app.prediction.AppPredictor;
+import android.app.prediction.AppTarget;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -98,6 +99,7 @@
private int mValidServiceTargetsNum = 0;
private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>>
mParkingDirectShareTargets = new HashMap<>();
+ private final Map<ComponentName, Map<String, Integer>> mChooserTargetScores = new HashMap<>();
private Set<ComponentName> mPendingChooserTargetService = new HashSet<>();
private Set<ComponentName> mShortcutComponents = new HashSet<>();
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
@@ -409,6 +411,15 @@
return null;
}
+ /**
+ * Fetch surfaced direct share target info
+ */
+ public List<ChooserTargetInfo> getSurfacedTargetInfo() {
+ int maxSurfacedTargets = mChooserListCommunicator.getMaxRankedTargets();
+ return mServiceTargets.subList(0,
+ Math.min(maxSurfacedTargets, getSelectableServiceTargetCount()));
+ }
+
/**
* Evaluate targets for inclusion in the direct share area. May not be included
@@ -480,6 +491,50 @@
}
/**
+ * Store ChooserTarget ranking scores info wrapped in {@code targets}.
+ */
+ public void addChooserTargetRankingScore(List<AppTarget> targets) {
+ Log.i(TAG, "addChooserTargetRankingScore " + targets.size() + " targets score.");
+ for (AppTarget target : targets) {
+ if (target.getShortcutInfo() == null) {
+ continue;
+ }
+ ShortcutInfo shortcutInfo = target.getShortcutInfo();
+ if (!shortcutInfo.getId().equals(ChooserActivity.CHOOSER_TARGET)
+ || shortcutInfo.getActivity() == null) {
+ continue;
+ }
+ ComponentName componentName = shortcutInfo.getActivity();
+ if (!mChooserTargetScores.containsKey(componentName)) {
+ mChooserTargetScores.put(componentName, new HashMap<>());
+ }
+ mChooserTargetScores.get(componentName).put(shortcutInfo.getShortLabel().toString(),
+ shortcutInfo.getRank());
+ }
+ mChooserTargetScores.keySet().forEach(key -> rankTargetsWithinComponent(key));
+ }
+
+ /**
+ * Rank chooserTargets of the given {@code componentName} in mParkingDirectShareTargets as per
+ * available scores stored in mChooserTargetScores.
+ */
+ private void rankTargetsWithinComponent(ComponentName componentName) {
+ if (!mParkingDirectShareTargets.containsKey(componentName)
+ || !mChooserTargetScores.containsKey(componentName)) {
+ return;
+ }
+ Map<String, Integer> scores = mChooserTargetScores.get(componentName);
+ Collections.sort(mParkingDirectShareTargets.get(componentName).first, (o1, o2) -> {
+ // The score has been normalized between 0 and 2, the default is 1.
+ int score1 = scores.getOrDefault(
+ ChooserUtil.md5(o1.getChooserTarget().getTitle().toString()), 1);
+ int score2 = scores.getOrDefault(
+ ChooserUtil.md5(o2.getChooserTarget().getTitle().toString()), 1);
+ return score2 - score1;
+ });
+ }
+
+ /**
* Park {@code targets} into memory for the moment to surface them later when view is refreshed.
* Components pending on ChooserTargetService query are also recorded.
*/
@@ -517,6 +572,7 @@
new Pair<>(new ArrayList<>(), 0));
parkingTargetInfoPair.first.addAll(parkingTargetInfos);
mParkingDirectShareTargets.put(origComponentName, parkingTargetInfoPair);
+ rankTargetsWithinComponent(origComponentName);
if (isShortcutResult) {
mShortcutComponents.add(origComponentName);
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 57157f7..774be3c 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -37,15 +37,18 @@
private static final int SINGLE_CELL_SPAN_SIZE = 1;
private final ChooserProfileDescriptor[] mItems;
+ private final boolean mIsSendAction;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
UserHandle personalProfileUserHandle,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ boolean isSendAction) {
super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
createProfileDescriptor(adapter)
};
+ mIsSendAction = isSendAction;
}
ChooserMultiProfilePagerAdapter(Context context,
@@ -53,13 +56,15 @@
ChooserActivity.ChooserGridAdapter workAdapter,
@Profile int defaultProfile,
UserHandle personalProfileUserHandle,
- UserHandle workProfileUserHandle) {
+ UserHandle workProfileUserHandle,
+ boolean isSendAction) {
super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
workProfileUserHandle);
mItems = new ChooserProfileDescriptor[] {
createProfileDescriptor(personalAdapter),
createProfileDescriptor(workAdapter)
};
+ mIsSendAction = isSendAction;
}
private ChooserProfileDescriptor createProfileDescriptor(
@@ -182,34 +187,62 @@
@Override
protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_work_apps,
- R.string.resolver_cant_share_with_work_apps_explanation);
+ if (mIsSendAction) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_work_apps,
+ R.string.resolver_cant_share_with_work_apps_explanation);
+ } else {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_work_apps,
+ R.string.resolver_cant_access_work_apps_explanation);
+ }
}
@Override
protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_personal_apps,
- R.string.resolver_cant_share_with_personal_apps_explanation);
+ if (mIsSendAction) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_personal_apps,
+ R.string.resolver_cant_share_with_personal_apps_explanation);
+ } else {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_personal_apps,
+ R.string.resolver_cant_access_personal_apps_explanation);
+ }
}
@Override
protected void showNoPersonalAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
- showEmptyState(listAdapter,
- R.drawable.ic_no_apps,
- R.string.resolver_no_personal_apps_available_share,
- /* subtitleRes */ 0);
+ if (mIsSendAction) {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_personal_apps_available_share,
+ /* subtitleRes */ 0);
+ } else {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_personal_apps_available_resolve,
+ /* subtitleRes */ 0);
+ }
}
@Override
protected void showNoWorkAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
- showEmptyState(listAdapter,
- R.drawable.ic_no_apps,
- R.string.resolver_no_work_apps_available_share,
- /* subtitleRes */ 0);
+ if (mIsSendAction) {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_work_apps_available_share,
+ /* subtitleRes */ 0);
+ } else {
+ showEmptyState(listAdapter,
+ R.drawable.ic_no_apps,
+ R.string.resolver_no_work_apps_available_resolve,
+ /* subtitleRes */ 0);
+ }
}
class ChooserProfileDescriptor extends ProfileDescriptor {
diff --git a/core/java/com/android/internal/app/ChooserUtil.java b/core/java/com/android/internal/app/ChooserUtil.java
new file mode 100644
index 0000000..3f8788c
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserUtil.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Utility method for common computation operations for Share sheet.
+ */
+public class ChooserUtil {
+
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /**
+ * Hashes the given input based on MD5 algorithm.
+ *
+ * @return a string representation of the hash computation.
+ */
+ public static String md5(String input) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(input.getBytes(UTF_8));
+ return convertBytesToHexString(md.digest());
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /** Converts byte array input into an hex string. */
+ private static String convertBytesToHexString(byte[] input) {
+ char[] chars = new char[input.length * 2];
+ for (int i = 0; i < input.length; i++) {
+ byte b = input[i];
+ chars[i * 2] = Character.forDigit((b >> 4) & 0xF, 16 /* radix */);
+ chars[i * 2 + 1] = Character.forDigit(b & 0xF, 16 /* radix */);
+ }
+ return new String(chars);
+ }
+
+ private ChooserUtil() {}
+}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9218823..06c21ab 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -27,6 +27,7 @@
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsAsyncNotedCallback;
import com.android.internal.app.IAppOpsNotedCallback;
+import com.android.internal.app.IAppOpsStartedCallback;
import com.android.internal.app.MessageSamplingConfig;
interface IAppOpsService {
@@ -91,6 +92,9 @@
void stopWatchingActive(IAppOpsActiveCallback callback);
boolean isOperationActive(int code, int uid, String packageName);
+ void startWatchingStarted(in int[] ops, IAppOpsStartedCallback callback);
+ void stopWatchingStarted(IAppOpsStartedCallback callback);
+
void startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback);
void startWatchingNoted(in int[] ops, IAppOpsNotedCallback callback);
diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
new file mode 100644
index 0000000..ed521e6
--- /dev/null
+++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+// Iterface to observe op starts
+oneway interface IAppOpsStartedCallback {
+ void opStarted(int op, int uid, String packageName, int mode);
+}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 2c48925..fca156a 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -80,6 +80,12 @@
protected ExecutorService mExecutorService;
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mExecutorService.shutdown();
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInjector = createInjector();
@@ -121,16 +127,19 @@
final int callingUserId = getUserId();
final Intent newIntent = canForward(intentReceived, getUserId(), targetUserId,
mInjector.getIPackageManager(), getContentResolver());
- if (newIntent != null) {
- newIntent.prepareToLeaveUser(callingUserId);
- maybeShowDisclosureAsync(intentReceived, newIntent, targetUserId, userMessageId);
- CompletableFuture.runAsync(() -> startActivityAsCaller(
- newIntent, targetUserId), mExecutorService);
- } else {
+
+ if (newIntent == null) {
Slog.wtf(TAG, "the intent: " + intentReceived + " cannot be forwarded from user "
+ callingUserId + " to user " + targetUserId);
+ finish();
+ return;
}
- finish();
+
+ newIntent.prepareToLeaveUser(callingUserId);
+ maybeShowDisclosureAsync(intentReceived, newIntent, targetUserId, userMessageId);
+ CompletableFuture.runAsync(() ->
+ startActivityAsCaller(newIntent, targetUserId), mExecutorService)
+ .thenAcceptAsync(result -> finish(), getApplicationContext().getMainExecutor());
}
private void maybeShowDisclosureAsync(
@@ -166,8 +175,6 @@
Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package "
+ launchedFromPackage + ", while running in "
+ ActivityThread.currentProcessName(), e);
- } finally {
- mExecutorService.shutdown();
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 2f62f8e..83dabe8 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -182,6 +182,8 @@
private BroadcastReceiver mWorkProfileStateReceiver;
private UserHandle mHeaderCreatorUser;
+ private UserHandle mWorkProfileUserHandle;
+
/**
* Get the string resource to be used as a label for the link to the resolver activity for an
* action.
@@ -363,6 +365,7 @@
// a more complicated UI that the current voice interaction flow is not able
// to handle.
boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
+ mWorkProfileUserHandle = fetchWorkProfileUserProfile();
mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
if (configureContentView()) {
return;
@@ -527,13 +530,18 @@
return UserHandle.of(ActivityManager.getCurrentUser());
}
protected @Nullable UserHandle getWorkProfileUserHandle() {
+ return mWorkProfileUserHandle;
+ }
+
+ protected @Nullable UserHandle fetchWorkProfileUserProfile() {
+ mWorkProfileUserHandle = null;
UserManager userManager = getSystemService(UserManager.class);
for (final UserInfo userInfo : userManager.getProfiles(ActivityManager.getCurrentUser())) {
if (userInfo.isManagedProfile()) {
- return userInfo.getUserHandle();
+ mWorkProfileUserHandle = userInfo.getUserHandle();
}
}
- return null;
+ return mWorkProfileUserHandle;
}
private boolean hasWorkProfile() {
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 2fd938f..24bf98b 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -54,6 +54,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.SelectableTargetInfo;
import com.android.internal.app.chooser.TargetInfo;
import java.util.ArrayList;
@@ -549,6 +550,15 @@
getLoadLabelTask((DisplayResolveInfo) info, holder).execute();
} else {
holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo());
+ if (info instanceof SelectableTargetInfo) {
+ // direct share targets should append the application name for a better readout
+ DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
+ CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
+ CharSequence extendedInfo = info.getExtendedInfo();
+ String contentDescription = String.join(" ", info.getDisplayLabel(),
+ extendedInfo != null ? extendedInfo : "", appName);
+ holder.updateContentDescription(contentDescription);
+ }
}
if (info.isSuspended()) {
@@ -697,6 +707,12 @@
text2.setVisibility(View.VISIBLE);
text2.setText(subLabel);
}
+
+ itemView.setContentDescription(null);
+ }
+
+ public void updateContentDescription(String description) {
+ itemView.setContentDescription(description);
}
}
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 246a07d..900e18d 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -44,7 +44,6 @@
import com.android.internal.app.SimpleIconFactory;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -136,6 +135,10 @@
return mIsSuspended;
}
+ public DisplayResolveInfo getDisplayResolveInfo() {
+ return mSourceInfo;
+ }
+
private Drawable getChooserTargetIconDrawable(ChooserTarget target,
@Nullable ShortcutInfo shortcutInfo) {
Drawable directShareIcon = null;
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index dea3566..8fef837 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -288,7 +288,7 @@
/**
* All known sources for this target component... uid -> process name -> source state.
*/
- private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();
+ final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();
private static final SourceKey sTmpSourceKey = new SourceKey(0, null, null);
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
index 7a6301f..a2eca3a 100644
--- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -45,4 +45,9 @@
*/
long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate,
out List<ParcelFileDescriptor> committedStats, out ProcessStats mergedStats);
+
+ /**
+ * @return The threshold to decide if a given association should be dumped into metrics.
+ */
+ long getMinAssociationDumpDuration();
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index fe41385..b814260 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -50,6 +50,7 @@
import android.service.procstats.ProcessStatsProto;
import android.service.procstats.ProcessStatsStateProto;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.LongSparseArray;
@@ -59,6 +60,7 @@
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
+import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats.PackageState;
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
@@ -1420,7 +1422,8 @@
/** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
- String procName, int uid, long now) {
+ String procName, int uid, long now,
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap) {
// Group proc stats by aggregated type (only screen state + process state)
SparseLongArray durationByState = new SparseLongArray();
boolean didCurState = false;
@@ -1524,6 +1527,8 @@
proto.end(stateToken);
}
+ mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
+ now, this, procToPkgMap);
proto.end(token);
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 80f6272..928ba35 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -20,12 +20,16 @@
import android.os.Debug;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.procstats.ProcessStatsAssociationProto;
import android.service.procstats.ProcessStatsAvailablePagesProto;
import android.service.procstats.ProcessStatsPackageProto;
import android.service.procstats.ProcessStatsSectionProto;
+import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -38,6 +42,8 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
+import com.android.internal.app.procstats.AssociationState.SourceKey;
+import com.android.internal.app.procstats.AssociationState.SourceState;
import dalvik.system.VMRuntime;
@@ -2229,6 +2235,8 @@
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto) {
dumpProtoPreamble(proto);
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap =
+ collectProcessPackageMaps(null, false);
for (int ip = 0; ip < procMap.size(); ip++) {
final String procName = procMap.keyAt(ip);
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
@@ -2237,7 +2245,7 @@
final ProcessState procState = uids.valueAt(iu);
procState.dumpAggregatedProtoForStatsd(proto,
ProcessStatsSectionProto.PROCESS_STATS,
- procName, uid, mTimePeriodEndRealtime);
+ procName, uid, mTimePeriodEndRealtime, procToPkgMap);
}
}
}
@@ -2268,6 +2276,135 @@
}
}
+ /**
+ * Walk through the known processes and build up the process -> packages map if necessary.
+ */
+ public ProcessMap<ArraySet<PackageState>> collectProcessPackageMaps(
+ String reqPackage, boolean activeOnly) {
+ final ProcessMap<ArraySet<PackageState>> map = new ProcessMap<>();
+
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
+ for (int ip = pkgMap.size() - 1; ip >= 0; ip--) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+ for (int iu = procs.size() - 1; iu >= 0; iu--) {
+ final LongSparseArray<PackageState> vpkgs = procs.valueAt(iu);
+ for (int iv = vpkgs.size() - 1; iv >= 0; iv--) {
+ final PackageState state = vpkgs.valueAt(iv);
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ for (int iproc = state.mProcesses.size() - 1; iproc >= 0; iproc--) {
+ final ProcessState proc = state.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ continue;
+ }
+
+ final String name = proc.getName();
+ final int uid = proc.getUid();
+ ArraySet<PackageState> pkgStates = map.get(name, uid);
+ if (pkgStates == null) {
+ pkgStates = new ArraySet<>();
+ map.put(name, uid, pkgStates);
+ }
+ pkgStates.add(state);
+ }
+ }
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Dump the association states related to given process into statsd.
+ *
+ * <p> Note: Only dump the single-package process state, or the common process state of
+ * multi-package process; while the per-package process state of a multi-package process
+ * should not be dumped into the statsd due to its incompletion.</p>
+ *
+ * @param proto The proto output stream
+ * @param fieldId The proto output field ID
+ * @param now The timestamp when the dump was initiated.
+ * @param procState The target process where its association states should be dumped.
+ * @param proc2Pkg The map between process to packages running within it.
+ */
+ public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
+ long fieldId, long now, ProcessState procState,
+ final ProcessMap<ArraySet<PackageState>> proc2Pkg) {
+ if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
+ // It's a per-package process state, don't bother to write into statsd
+ return;
+ }
+ ArrayMap<SourceKey, long[]> assocVals = new ArrayMap<>();
+ final String procName = procState.getName();
+ final int procUid = procState.getUid();
+ final long procVersion = procState.getVersion();
+ final ArraySet<PackageState> packages = proc2Pkg.get(procName, procUid);
+ if (packages == null || packages.isEmpty()) {
+ // Shouldn't happen
+ return;
+ }
+ for (int i = packages.size() - 1; i >= 0; i--) {
+ final PackageState pkgState = packages.valueAt(i);
+ final ArrayMap<String, AssociationState> associations = pkgState.mAssociations;
+ for (int j = associations.size() - 1; j >= 0; j--) {
+ final AssociationState assoc = associations.valueAt(j);
+ // Make sure this association is really about this process
+ if (!TextUtils.equals(assoc.getProcessName(), procName)) {
+ continue;
+ }
+ final ArrayMap<SourceKey, SourceState> sources = assoc.mSources;
+ for (int k = sources.size() - 1; k >= 0; k--) {
+ final SourceKey key = sources.keyAt(k);
+ final SourceState state = sources.valueAt(k);
+ long[] vals = assocVals.get(key);
+ if (vals == null) {
+ vals = new long[2];
+ assocVals.put(key, vals);
+ }
+ vals[0] += state.mDuration;
+ vals[1] += state.mCount;
+ if (state.mNesting > 0) {
+ vals[0] += now - state.mStartUptime;
+ }
+ }
+ }
+ }
+ final IProcessStats procStatsService = IProcessStats.Stub.asInterface(
+ ServiceManager.getService(SERVICE_NAME));
+ if (procStatsService != null) {
+ try {
+ final long minimum = procStatsService.getMinAssociationDumpDuration();
+ if (minimum > 0) {
+ // Now filter out unnecessary ones.
+ for (int i = assocVals.size() - 1; i >= 0; i--) {
+ final long[] vals = assocVals.valueAt(i);
+ if (vals[0] < minimum) {
+ assocVals.removeAt(i);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ // ignore.
+ }
+ }
+ if (!assocVals.isEmpty()) {
+ for (int i = assocVals.size() - 1; i >= 0; i--) {
+ final SourceKey key = assocVals.keyAt(i);
+ final long[] vals = assocVals.valueAt(i);
+ final long token = proto.start(fieldId);
+ proto.write(ProcessStatsAssociationProto.ASSOC_PROCESS_NAME, key.mProcess);
+ proto.write(ProcessStatsAssociationProto.ASSOC_PACKAGE_NAME, key.mPackage);
+ proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]);
+ proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
+ (int) (vals[0] / 1000));
+ proto.end(token);
+ }
+ }
+ }
+
final public static class ProcessStateHolder {
public final long appVersion;
public ProcessState state;
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 837cc46..6f33096 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -210,7 +210,7 @@
* Allow touch passthrough above assist area during a session.
*/
public static final String ASSIST_TAP_PASSTHROUGH = "assist_tap_passthrough";
-
+
/**
* (bool) Whether to show handles when taught.
*/
@@ -389,10 +389,30 @@
public static final String APPEND_DIRECT_SHARE_ENABLED = "append_direct_share_enabled";
/**
+ * (boolean) Whether ChooserTargets ranking on Sharesheet is enabled.
+ */
+ public static final String CHOOSER_TARGET_RANKING_ENABLED = "chooser_target_ranking_enabled";
+
+ /**
* (boolean) Whether to enable user-drag resizing for PIP.
*/
public static final String PIP_USER_RESIZE = "pip_user_resize";
+ /**
+ * (float) Bottom height in DP for Back Gesture.
+ */
+ public static final String BACK_GESTURE_BOTTOM_HEIGHT = "back_gesture_bottom_height";
+
+ /**
+ * (float) Edge width in DP where touch down is allowed for Back Gesture.
+ */
+ public static final String BACK_GESTURE_EDGE_WIDTH = "back_gesture_edge_width";
+
+ /**
+ * (float) Slop multiplier for Back Gesture.
+ */
+ public static final String BACK_GESTURE_SLOP_MULTIPLIER = "back_gesture_slop_multiplier";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 3900f16..7195b45a 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -321,6 +321,20 @@
obtainMessage(AbstractRemoteService::handlePendingRequest, this, asyncRequest));
}
+ /**
+ * Executes an async request immediately instead of sending it to Handler queue as what
+ * {@link scheduleAsyncRequest} does.
+ *
+ * <p>This request is not expecting a callback from the service, hence it's represented by
+ * a simple {@link Runnable}.
+ */
+ protected void executeAsyncRequest(@NonNull AsyncRequest<I> request) {
+ // TODO(b/117779333): fix generics below
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
+ handlePendingRequest(asyncRequest);
+ }
+
private void cancelScheduledUnbind() {
mHandler.removeMessages(MSG_UNBIND);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 863659d..c6135f2 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -324,6 +324,14 @@
return mBackgroundFallback.getDrawable();
}
+ @Nullable View getStatusBarBackgroundView() {
+ return mStatusColorViewState.view;
+ }
+
+ @Nullable View getNavigationBarBackgroundView() {
+ return mNavigationColorViewState.view;
+ }
+
@Override
public boolean gatherTransparentRegion(Region region) {
boolean statusOpaque = gatherTransparentRegion(mStatusColorViewState, region);
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 56a6db9..0e703fa 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -16,13 +16,18 @@
package com.android.internal.policy;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BACK_GESTURE_EDGE_WIDTH;
+
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
/**
* @hide
@@ -30,14 +35,27 @@
public class GestureNavigationSettingsObserver extends ContentObserver {
private Context mContext;
private Runnable mOnChangeRunnable;
+ private Handler mMainHandler;
public GestureNavigationSettingsObserver(Handler handler, Context context,
Runnable onChangeRunnable) {
super(handler);
+ mMainHandler = handler;
mContext = context;
mOnChangeRunnable = onChangeRunnable;
}
+ private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())
+ && mOnChangeRunnable != null) {
+ mOnChangeRunnable.run();
+ }
+ }
+ };
+
public void register() {
ContentResolver r = mContext.getContentResolver();
r.registerContentObserver(
@@ -49,10 +67,15 @@
r.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
false, this, UserHandle.USER_ALL);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ runnable -> mMainHandler.post(runnable),
+ mOnPropertiesChangedListener);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
+ DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
}
@Override
@@ -77,8 +100,13 @@
}
private int getSensitivity(Resources userRes, String side) {
- final int inset = userRes.getDimensionPixelSize(
- com.android.internal.R.dimen.config_backGestureInset);
+ final DisplayMetrics dm = userRes.getDisplayMetrics();
+ final float defaultInset = userRes.getDimension(
+ com.android.internal.R.dimen.config_backGestureInset) / dm.density;
+ final float backGestureInset = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+ BACK_GESTURE_EDGE_WIDTH, defaultInset);
+ final float inset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, backGestureInset,
+ dm);
final float scale = Settings.Secure.getFloatForUser(
mContext.getContentResolver(), side, 1.0f, UserHandle.USER_CURRENT);
return (int) (inset * scale);
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index aa75d40..c5729b0 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -38,6 +38,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.SearchManager;
@@ -3949,4 +3950,16 @@
public void removeScrollCaptureCallback(@NonNull ScrollCaptureCallback callback) {
getViewRootImpl().removeScrollCaptureCallback(callback);
}
+
+ @Override
+ @Nullable
+ public View getStatusBarBackgroundView() {
+ return mDecor != null ? mDecor.getStatusBarBackgroundView() : null;
+ }
+
+ @Override
+ @Nullable
+ public View getNavigationBarBackgroundView() {
+ return mDecor != null ? mDecor.getNavigationBarBackgroundView() : null;
+ }
}
diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
index 1fce098..1ec0206 100644
--- a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
+++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java
@@ -91,14 +91,14 @@
int width = right - left;
int height = bottom - top;
if ((ctrlType & CTRL_LEFT) != 0) {
- width = Math.max(minVisibleWidth, width - deltaX);
+ width = Math.max(minVisibleWidth, Math.min(width - deltaX, maxVisibleSize.x));
} else if ((ctrlType & CTRL_RIGHT) != 0) {
- width = Math.max(minVisibleWidth, width + deltaX);
+ width = Math.max(minVisibleWidth, Math.min(width + deltaX, maxVisibleSize.x));
}
if ((ctrlType & CTRL_TOP) != 0) {
- height = Math.max(minVisibleHeight, height - deltaY);
+ height = Math.max(minVisibleHeight, Math.min(height - deltaY, maxVisibleSize.y));
} else if ((ctrlType & CTRL_BOTTOM) != 0) {
- height = Math.max(minVisibleHeight, height + deltaY);
+ height = Math.max(minVisibleHeight, Math.min(height + deltaY, maxVisibleSize.y));
}
// If we have to preserve the orientation - check that we are doing so.
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 38f5f32..8c5fdf5 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -137,7 +137,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ long operationId, int sysUiSessionId);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 24fe063..c320824 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -106,7 +106,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ long operationId, int sysUiSessionId);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index 9168438..05ecdf9 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -21,6 +21,7 @@
import android.util.ExceptionUtils;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -196,6 +197,32 @@
}
/**
+ * A {@link BiFunction} that allows throwing checked exceptions from its single abstract method.
+ *
+ * Can be used together with {@link #uncheckExceptions} to effectively turn a lambda expression
+ * that throws a checked exception into a regular {@link BiFunction}
+ *
+ * @param <T> see {@link BiFunction}
+ * @param <U> see {@link BiFunction}
+ * @param <R> see {@link BiFunction}
+ */
+ @FunctionalInterface
+ @SuppressWarnings("FunctionalInterfaceMethodChanged")
+ public interface ThrowingBiFunction<T, U, R> extends BiFunction<T, U, R> {
+ /** @see ThrowingFunction */
+ R applyOrThrow(T t, U u) throws Exception;
+
+ @Override
+ default R apply(T t, U u) {
+ try {
+ return applyOrThrow(t, u);
+ } catch (Exception ex) {
+ throw ExceptionUtils.propagate(ex);
+ }
+ }
+ }
+
+ /**
* A {@link BiConsumer} that allows throwing checked exceptions from its single abstract method.
*
* Can be used together with {@link #uncheckExceptions} to effectively turn a lambda expression
diff --git a/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
index 08a349c..78df3eb 100644
--- a/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
+++ b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl
@@ -24,4 +24,6 @@
*/
oneway interface IInlineContentProvider {
void provideContent(int width, int height, in IInlineContentCallback callback);
+ void requestSurfacePackage();
+ void onSurfacePackageReleased();
}
diff --git a/core/java/com/android/internal/widget/GridLayoutManager.java b/core/java/com/android/internal/widget/GridLayoutManager.java
index e0502f1..09e6a99 100644
--- a/core/java/com/android/internal/widget/GridLayoutManager.java
+++ b/core/java/com/android/internal/widget/GridLayoutManager.java
@@ -153,13 +153,11 @@
if (mOrientation == HORIZONTAL) {
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
glp.getSpanIndex(), glp.getSpanSize(),
- spanGroupIndex, 1,
- mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+ spanGroupIndex, 1, false, false));
} else { // VERTICAL
info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
spanGroupIndex, 1,
- glp.getSpanIndex(), glp.getSpanSize(),
- mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+ glp.getSpanIndex(), glp.getSpanSize(), false, false));
}
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 90a18ef..38588ea 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -107,4 +107,10 @@
* @return true if the arming worked
*/
public abstract boolean armRebootEscrow();
+
+
+ /**
+ * Refreshes pending strong auth timeout with the latest admin requirement set by device policy.
+ */
+ public abstract void refreshStrongAuthTimeout(int userId);
}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index fb2ecf3..3f708f8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -825,18 +825,6 @@
return true;
}
break;
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
- case R.id.accessibilityActionScrollUp:
- if (mCollapseOffset < mCollapsibleHeight) {
- smoothScrollTo(mCollapsibleHeight, 0);
- return true;
- } else if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
- && isDismissable()) {
- smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0);
- mDismissOnScrollerFinished = true;
- return true;
- }
- break;
case AccessibilityNodeInfo.ACTION_COLLAPSE:
if (mCollapseOffset < mCollapsibleHeight) {
smoothScrollTo(mCollapsibleHeight, 0);
@@ -886,7 +874,6 @@
}
if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight)
&& ((mCollapseOffset < mCollapsibleHeight) || isDismissable())) {
- info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(AccessibilityAction.ACTION_SCROLL_UP);
info.setScrollable(true);
}
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index c523e2d..9ad4cd9 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -162,20 +162,23 @@
extern "C" {
-static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
-static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName, jlong vendorId);
-static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName);
-static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId);
-static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag);
-static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong ptr,
+ jclass keyType);
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName,
+ jlong vendorId);
+static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jclass thiz, jlong ptr,
+ jstring keyName);
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jclass thiz, jint tag, jlong vendorId);
+static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jclass thiz, jlong ptr, jint tag);
+static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jclass thiz);
+
+static std::shared_ptr<CameraMetadata>* CameraMetadata_getSharedPtr(jlong metadataLongPtr) {
+ return reinterpret_cast<std::shared_ptr<CameraMetadata>* >(metadataLongPtr);
+}
// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
-static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
- if (thiz == nullptr) {
- return nullptr;
- }
- auto metadata = reinterpret_cast<std::shared_ptr<CameraMetadata> *>(
- env->GetLongField(thiz, fields.metadata_ptr));
+static CameraMetadata* CameraMetadata_getPointerNoThrow(jlong ptr) {
+ auto metadata = CameraMetadata_getSharedPtr(ptr);
if (metadata == nullptr) {
return nullptr;
}
@@ -183,40 +186,31 @@
}
// Safe access to native pointer from object. Throws if not possible to access.
-static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
+static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jlong ptr,
const char* argName = "this") {
-
- if (thiz == NULL) {
- ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
- __FUNCTION__);
- jniThrowNullPointerException(env, argName);
- return NULL;
- }
-
- CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
- if (metadata == NULL) {
+ CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
+ if (metadata == nullptr) {
ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
__FUNCTION__);
jniThrowException(env, "java/lang/IllegalStateException",
"Metadata object was already closed");
- return NULL;
+ return nullptr;
}
return metadata;
}
-static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
+static jlong CameraMetadata_allocate(JNIEnv *env, jclass thiz) {
ALOGV("%s", __FUNCTION__);
return reinterpret_cast<jlong>(new std::shared_ptr<CameraMetadata>(new CameraMetadata()));
}
-static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
- jobject other) {
+static jlong CameraMetadata_allocateCopy(JNIEnv *env, jclass thiz, jlong other) {
ALOGV("%s", __FUNCTION__);
CameraMetadata* otherMetadata =
- CameraMetadata_getPointerThrow(env, other, "other");
+ CameraMetadata_getPointerThrow(env, other);
// In case of exception, return
if (otherMetadata == NULL) return NULL;
@@ -226,10 +220,10 @@
}
-static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
+static jboolean CameraMetadata_isEmpty(JNIEnv *env, jclass thiz, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) {
ALOGW("%s: Returning early due to exception being thrown",
@@ -245,10 +239,10 @@
return empty;
}
-static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
+static jint CameraMetadata_getEntryCount(JNIEnv *env, jclass thiz, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return 0; // actually throws java exc.
@@ -256,42 +250,33 @@
}
// idempotent. calling more than once has no effect.
-static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
+static void CameraMetadata_close(JNIEnv *env, jclass thiz, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- if (thiz != nullptr) {
- auto metadata = reinterpret_cast<std::shared_ptr<CameraMetadata> *>(
- env->GetLongField(thiz, fields.metadata_ptr));
- if (metadata != nullptr) {
- delete metadata;
- env->SetLongField(thiz, fields.metadata_ptr, 0);
- }
+ auto metadata = CameraMetadata_getSharedPtr(ptr);
+ if (metadata != nullptr) {
+ delete metadata;
}
-
- LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != nullptr,
- "Expected the native ptr to be 0 after #close");
}
-static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
+static void CameraMetadata_swap(JNIEnv *env, jclass thiz, jlong ptr, jlong other) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ auto metadata = CameraMetadata_getSharedPtr(ptr);
+ auto otherMetadata = CameraMetadata_getSharedPtr(other);
- // order is important: we can't call another JNI method
- // if there is an exception pending
if (metadata == NULL) return;
-
- CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
-
if (otherMetadata == NULL) return;
+ // Need to swap shared pointers, not CameraMetadata, since the latter may be in use
+ // by an NDK client, and we don't want to swap their data out from under them.
metadata->swap(*otherMetadata);
}
-static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
+static jbyteArray CameraMetadata_readValues(JNIEnv *env, jclass thiz, jint tag, jlong ptr) {
ALOGV("%s (tag = %d)", __FUNCTION__, tag);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return NULL;
const camera_metadata_t *metaBuffer = metadata->getAndLock();
@@ -327,10 +312,11 @@
return byteArray;
}
-static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
+static void CameraMetadata_writeValues(JNIEnv *env, jclass thiz, jint tag, jbyteArray src,
+ jlong ptr) {
ALOGV("%s (tag = %d)", __FUNCTION__, tag);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return;
const camera_metadata_t *metaBuffer = metadata->getAndLock();
@@ -400,9 +386,9 @@
return NULL;
}
-static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
+static void CameraMetadata_dump(JNIEnv *env, jclass thiz, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) {
return;
}
@@ -496,9 +482,9 @@
}
}
-static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
+static void CameraMetadata_readFromParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) {
return;
}
@@ -517,9 +503,9 @@
}
}
-static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
+static void CameraMetadata_writeToParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
ALOGV("%s", __FUNCTION__);
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) {
return;
}
@@ -558,44 +544,44 @@
"()J",
(void*)CameraMetadata_allocate },
{ "nativeAllocateCopy",
- "(L" CAMERA_METADATA_CLASS_NAME ";)J",
+ "(J)J",
(void *)CameraMetadata_allocateCopy },
{ "nativeIsEmpty",
- "()Z",
+ "(J)Z",
(void*)CameraMetadata_isEmpty },
{ "nativeGetEntryCount",
- "()I",
+ "(J)I",
(void*)CameraMetadata_getEntryCount },
{ "nativeClose",
- "()V",
+ "(J)V",
(void*)CameraMetadata_close },
{ "nativeSwap",
- "(L" CAMERA_METADATA_CLASS_NAME ";)V",
+ "(JJ)V",
(void *)CameraMetadata_swap },
{ "nativeGetTagFromKeyLocal",
- "(Ljava/lang/String;)I",
+ "(JLjava/lang/String;)I",
(void *)CameraMetadata_getTagFromKeyLocal },
{ "nativeGetTypeFromTagLocal",
- "(I)I",
+ "(JI)I",
(void *)CameraMetadata_getTypeFromTagLocal },
{ "nativeReadValues",
- "(I)[B",
+ "(IJ)[B",
(void *)CameraMetadata_readValues },
{ "nativeWriteValues",
- "(I[B)V",
+ "(I[BJ)V",
(void *)CameraMetadata_writeValues },
{ "nativeDump",
- "()V",
+ "(J)V",
(void *)CameraMetadata_dump },
{ "nativeGetAllVendorKeys",
- "(Ljava/lang/Class;)Ljava/util/ArrayList;",
+ "(JLjava/lang/Class;)Ljava/util/ArrayList;",
(void *)CameraMetadata_getAllVendorKeys},
// Parcelable interface
{ "nativeReadFromParcel",
- "(Landroid/os/Parcel;)V",
+ "(Landroid/os/Parcel;J)V",
(void *)CameraMetadata_readFromParcel },
{ "nativeWriteToParcel",
- "(Landroid/os/Parcel;)V",
+ "(Landroid/os/Parcel;J)V",
(void *)CameraMetadata_writeToParcel },
};
@@ -652,8 +638,8 @@
extern "C" {
-static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag) {
- CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jclass thiz, jlong ptr, jint tag) {
+ CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
if (metadata) {
const camera_metadata_t *metaBuffer = metadata->getAndLock();
@@ -671,7 +657,8 @@
return tagType;
}
-static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName) {
+static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jclass thiz, jlong ptr,
+ jstring keyName) {
ScopedUtfChars keyScoped(env, keyName);
const char *key = keyScoped.c_str();
if (key == NULL) {
@@ -682,7 +669,7 @@
uint32_t tag = 0;
sp<VendorTagDescriptor> vTags;
- CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
if (metadata) {
sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
if (cache.get()) {
@@ -701,7 +688,8 @@
return tag;
}
-static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong ptr,
+ jclass keyType) {
metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
// Get all vendor tags
sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
@@ -712,7 +700,7 @@
return nullptr;
}
- CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+ CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return NULL;
const camera_metadata_t *metaBuffer = metadata->getAndLock();
@@ -816,7 +804,7 @@
return arrayList;
}
-static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName,
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName,
jlong vendorId) {
ScopedUtfChars keyScoped(env, keyName);
const char *key = keyScoped.c_str();
@@ -844,7 +832,7 @@
return tag;
}
-static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId) {
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jclass thiz, jint tag, jlong vendorId) {
int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
if (tagType == -1) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
@@ -855,7 +843,7 @@
return tagType;
}
-static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
+static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jclass thiz) {
const String16 NAME("media.camera");
sp<hardware::ICameraService> cameraService;
status_t err = getService(NAME, /*out*/&cameraService);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5869787..36b4b6a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -174,8 +174,10 @@
jclass clazz;
jmethodID ctor;
jfieldID defaultConfig;
- jfieldID minRefreshRate;
- jfieldID maxRefreshRate;
+ jfieldID primaryRefreshRateMin;
+ jfieldID primaryRefreshRateMax;
+ jfieldID appRequestRefreshRateMin;
+ jfieldID appRequestRefreshRateMax;
} gDesiredDisplayConfigSpecsClassInfo;
class JNamedColorSpace {
@@ -919,13 +921,24 @@
jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
- jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
- jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);
+ jfloat primaryRefreshRateMin =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
+ jfloat primaryRefreshRateMax =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
+ jfloat appRequestRefreshRateMin =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin);
+ jfloat appRequestRefreshRateMax =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax);
- size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
- token, defaultConfig, minRefreshRate, maxRefreshRate);
+ size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(token, defaultConfig,
+ primaryRefreshRateMin,
+ primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
@@ -934,16 +947,23 @@
if (token == nullptr) return nullptr;
int32_t defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
- if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig, &minRefreshRate,
- &maxRefreshRate) != NO_ERROR) {
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
+ if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax) !=
+ NO_ERROR) {
return nullptr;
}
return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
- gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig, minRefreshRate,
- maxRefreshRate);
+ gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig,
+ primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1757,13 +1777,17 @@
gDesiredDisplayConfigSpecsClassInfo.clazz =
MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
gDesiredDisplayConfigSpecsClassInfo.ctor =
- GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
+ GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFFFF)V");
gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
- gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "minRefreshRate", "F");
- gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "maxRefreshRate", "F");
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMin", "F");
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMax", "F");
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMin", "F");
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
return err;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3a5720fd..c5bc083 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1552,8 +1552,8 @@
}
}
-static void BindMountStorageToLowerFs(const userid_t user_id, const char* dir_name,
- const char* package, fail_fn_t fail_fn) {
+static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid,
+ const char* dir_name, const char* package, fail_fn_t fail_fn) {
bool hasSdcardFs = IsFilesystemSupported("sdcardfs");
std::string source;
@@ -1565,6 +1565,9 @@
}
std::string target = StringPrintf("/storage/emulated/%d/%s/%s", user_id, dir_name, package);
+ // As the parent is mounted as tmpfs, we need to create the target dir here.
+ PrepareDirIfNotPresent(target, 0700, uid, uid, fail_fn);
+
if (access(source.c_str(), F_OK) != 0) {
fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno)));
}
@@ -1574,9 +1577,8 @@
BindMount(source, target, fail_fn);
}
-// Bind mount all obb & data directories that are visible to this app.
-// If app data isolation is not enabled for this process, bind mount the whole obb
-// and data directory instead.
+// Mount tmpfs on Android/data and Android/obb, then bind mount all app visible package
+// directories in data and obb directories.
static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {
@@ -1590,12 +1592,18 @@
fail_fn(CREATE_ERROR("Data package list cannot be empty"));
}
+ // Create tmpfs on Android/obb and Android/data so these 2 dirs won't enter fuse anymore.
+ std::string androidObbDir = StringPrintf("/storage/emulated/%d/Android/obb", user_id);
+ MountAppDataTmpFs(androidObbDir, fail_fn);
+ std::string androidDataDir = StringPrintf("/storage/emulated/%d/Android/data", user_id);
+ MountAppDataTmpFs(androidDataDir, fail_fn);
+
// Bind mount each package obb directory
for (int i = 0; i < size; i += 3) {
jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
std::string packageName = extract_fn(package_str).value();
- BindMountStorageToLowerFs(user_id, "Android/obb", packageName.c_str(), fail_fn);
- BindMountStorageToLowerFs(user_id, "Android/data", packageName.c_str(), fail_fn);
+ BindMountStorageToLowerFs(user_id, uid, "Android/obb", packageName.c_str(), fail_fn);
+ BindMountStorageToLowerFs(user_id, uid, "Android/data", packageName.c_str(), fail_fn);
}
}
@@ -1648,9 +1656,10 @@
uid, process_name, managed_nice_name, fail_fn);
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
- if (mount_external != MOUNT_EXTERNAL_INSTALLER &&
- mount_external != MOUNT_EXTERNAL_PASS_THROUGH &&
- mount_storage_dirs) {
+ // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
+ // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
+ // and hence they won't bind mount storage dirs.
+ if (mount_storage_dirs) {
BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d5384a1..762895b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -169,6 +169,7 @@
optional SettingProto boot_count = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto bugreport_in_power_menu = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto cached_apps_freezer_enabled = 152 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto call_auto_retry = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
message CaptivePortal {
@@ -1059,5 +1060,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 152;
+ // Next tag = 153;
}
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index a6dc937..dd830a8 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -142,7 +142,7 @@
optional android.util.AggStats rss = 8;
}
-// Next Tag: 7
+// Next Tag: 8
message ProcessStatsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -173,6 +173,25 @@
// Total time process has been running... screen_state, memory_state, and process_state
// will not be set.
optional ProcessStatsStateProto total_running_state = 6;
+
+ // Association data for this process in this state;
+ // each entry here is one association.
+ repeated ProcessStatsAssociationProto assocs = 7;
+}
+
+// Next Tag: 5
+message ProcessStatsAssociationProto {
+ // Procss Name of the associated process/package
+ optional string assoc_process_name = 1;
+
+ // Package Name of the associated process/package
+ optional string assoc_package_name = 2;
+
+ // Total count of the times this association appeared.
+ optional int32 total_count = 3;
+
+ // Uptime total duration in seconds this association was around.
+ optional int32 total_duration_secs = 4;
}
// Next Tag: 4
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a23277e..0bf5045 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5099,7 +5099,7 @@
</activity>
<activity android:name="com.android.internal.app.IntentForwarderActivity"
android:finishOnCloseSystemDialogs="true"
- android:theme="@style/Theme.NoDisplay"
+ android:theme="@style/Theme.Translucent.NoTitleBar"
android:excludeFromRecents="true"
android:label="@string/user_owner_label"
android:exported="true"
diff --git a/core/res/res/anim/dream_activity_close_exit.xml b/core/res/res/anim/dream_activity_close_exit.xml
new file mode 100644
index 0000000..c4599da
--- /dev/null
+++ b/core/res/res/anim/dream_activity_close_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="100" />
+
diff --git a/core/res/res/anim/dream_activity_open_enter.xml b/core/res/res/anim/dream_activity_open_enter.xml
new file mode 100644
index 0000000..9e1c6e2
--- /dev/null
+++ b/core/res/res/anim/dream_activity_open_enter.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- During this animation we keep the previous activity on the screen
+using a noop animation for it (dream_activity_open_exit). The duration of
+those two has to be the same. -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+
diff --git a/core/res/res/anim/dream_activity_open_exit.xml b/core/res/res/anim/dream_activity_open_exit.xml
new file mode 100644
index 0000000..740f528
--- /dev/null
+++ b/core/res/res/anim/dream_activity_open_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- A noop animation to keep the previous activity alive during the dream
+enter animation. The duration should match the duration of the
+dream_activity_open_enter animation. -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 696912b..955663f 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -20,21 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:startOffset="250"
- android:duration="167"/>
-
<translate android:fromYDelta="0" android:toYDelta="110%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/fast_out_linear_in"
android:duration="225"/>
-
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale="1.0" android:toYScale="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/fast_out_slow_in"
- android:duration="225" />
</set>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml
index 6b1b002..86dc71c 100644
--- a/core/res/res/layout/chooser_list_per_profile.xml
+++ b/core/res/res/layout/chooser_list_per_profile.xml
@@ -20,7 +20,7 @@
<com.android.internal.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layoutManager="com.android.internal.widget.GridLayoutManager"
+ android:layoutManager="com.android.internal.app.ChooserGridLayoutManager"
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:background="?attr/colorBackgroundFloating"
@@ -29,4 +29,4 @@
android:nestedScrollingEnabled="true" />
<include layout="@layout/resolver_empty_states" />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 4d0837f..446ce3f 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -83,6 +83,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
+ android:accessibilityTraversalAfter="@id/title"
android:background="?attr/colorBackgroundFloating">
<LinearLayout
android:orientation="vertical"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7024755..a1a84ae 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n\n•Skakel Donkertema aan\n•Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk hulle\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batterybespaarder doen die volgende om batterylewe te verleng:\n\n•Skakel Donkertema aan\n•Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk hulle"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kragdialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"het \'n prent gestuur"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Gesprek"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Groepsgesprek"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index df521e0..a32e691 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n\n•ጨለማ ገጽታን ያበራል\n•የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ «Hey Google» ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n\n•ጨለማ ገጽታን ያበራል\n•የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ «Hey Google» ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል"</string>
<string name="data_saver_description" msgid="4995164271550590517">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ውሂብ ቆጣቢ ይጥፋ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"አብራ"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"የኃይል መገናኛ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"አንድ ምስል ልከዋል"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ውይይት"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"የቡድን ውይይት"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ec04906..4faac2a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -208,12 +208,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"تفعيل الملف الشخصي للعمل"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"تم حظر تطبيقاتك الشخصية إلى أن تفعِّل ملفك الشخصي للعمل."</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"سيتم حظر تطبيقاتك الشخصية غدًا."</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"تفعيل الملف الشخصي للعمل"</string>
<string name="me" msgid="6207584824693813140">"أنا"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"خيارات الجهاز اللوحي"</string>
@@ -1889,10 +1886,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"لإطالة عمر البطارية، تعمل \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\".\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string>
@@ -2183,15 +2178,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"مربّع حوار الطاقة"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"هذا المستخدم أرسل صورة"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"محادثة"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"محادثة جماعية"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index ef193cb..b564707 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ, বেটাৰী সঞ্চয়কাৰীয়ে:\n\n•গাঢ় ৰঙৰ থীম অন কৰে\n•পটভূমিৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল প্ৰভাৱ আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সেইবোৰ সীমাবদ্ধ কৰে\n\n"<annotation id="url">"অধিক জানক"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ, বেটাৰী সঞ্চয়কাৰীয়ে:\n\n•গাঢ় ৰঙৰ থীম অন কৰে\n•পটভূমিৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল প্ৰভাৱ আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সেইবোৰ সীমাবদ্ধ কৰে"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰ মাত্ৰা কম কৰিবৰ বাবে ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা ব্য়ৱহাৰ কৰিব পাৰে, কিন্তু সঘনাই এই কার্য কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ এইয়ে হ\'ব পাৰে যে, উদাহৰণস্বৰূপে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"অন কৰক"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাৱাৰ ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"বাৰ্তালাপ"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গোটত কৰা বাৰ্তালাপ"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 2779029..0f0c717 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n•Qaranlıq temanı aktiv edir\n•Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n•Qaranlıq temanı aktiv edir\n•Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsinin və qəbulunun qarşısını alır. Hazırda işlətdiyiniz tətbiq dataya daxil ola bilər, ancaq bunu tez-tez edə bilməz. Bu o deməkdir ki, məsələn, Siz üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Data Qənaəti aktiv edilsin?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivləşdirin"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Yandırıb-söndürmə dialoqu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"şəkil göndərdi"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Söhbət"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Qrup Söhbəti"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d12073a92..61342ac 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -184,11 +184,11 @@
<item quantity="other">Instalirani su autoriteti za izdavanje sertifikata</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Od strane nepoznate treće strane"</string>
- <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Od strane administratora profila za Work"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Od strane administratora poslovnog profila"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Od strane <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="work_profile_deleted" msgid="5891181538182009328">"Poslovni profil je izbrisan"</string>
- <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacija za administratore na profilu za Work nedostaje ili je oštećena. Zbog toga su profil za Work i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
- <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil za Work više nije dostupan na ovom uređaju"</string>
+ <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacija za administratore na poslovnom profilu nedostaje ili je oštećena. Zbog toga su poslovni profil i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
+ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Poslovni profil više nije dostupan na ovom uređaju"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa lozinke"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator je ustupio uređaj za ličnu upotrebu"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja"</string>
@@ -202,10 +202,10 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Uključite profil za Work"</string>
- <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Lične aplikacije su blokirane dok ne uključite profil za Work"</string>
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Uključite poslovni profil"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Lične aplikacije su blokirane dok ne uključite poslovni profil"</string>
<string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Lične aplikacije će biti blokirane sutra"</string>
- <string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Uključi profil za Work"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Uključi poslovni profil"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije za tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string>
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n•uključuje tamnu temu\n•isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n•uključuje tamnu temu\n•isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -1887,7 +1885,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS zahtev je promenjen u video poziv"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS zahtev je promenjen u USSD zahtev"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Promenjeno je u novi SS zahtev"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil za Work"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Poslovni profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Obavešteno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Proširi"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Skupi"</string>
@@ -1922,8 +1920,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. <xliff:g id="APP_NAME_1">%2$s</xliff:g> upravlja dostupnošću."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opozovi pauziranje aplikacije"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo profil za Work?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije profila za Work"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo poslovni profil?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije poslovnog profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
@@ -1932,8 +1930,8 @@
<string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Otvorite aplikaciju za SMS da biste pregledali"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Neke funkcije su možda ograničene"</string>
- <string name="profile_encrypted_detail" msgid="5279730442756849055">"Profil za Work je zaključan"</string>
- <string name="profile_encrypted_message" msgid="1128512616293157802">"Dodirom otklj. profil za Work"</string>
+ <string name="profile_encrypted_detail" msgid="5279730442756849055">"Poslovni profil je zaključan"</string>
+ <string name="profile_encrypted_message" msgid="1128512616293157802">"Dodirom otklj. poslovni profil"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Povezano je sa proizvodom <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Dodirnite za pregled datoteka"</string>
<string name="pin_target" msgid="8036028973110156895">"Zakači"</string>
@@ -2078,15 +2076,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzacija"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupna konverzacija"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
@@ -2095,14 +2094,14 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Lični prikaz"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Prikaz za posao"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Ne možete da delite ovaj sadržaj pomoću aplikacija za posao"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT administrator vam ne dozvoljava da delite ovaj sadržaj pomoću aplikacija na profilu za Work"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT administrator vam ne dozvoljava da delite ovaj sadržaj pomoću aplikacija na poslovnom profilu"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Ne možete da otvorite ovaj sadržaj pomoću aplikacija za posao"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT administrator vam ne dozvoljava da otvorite ovaj sadržaj pomoću aplikacija na profilu za Work"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT administrator vam ne dozvoljava da otvorite ovaj sadržaj pomoću aplikacija na poslovnom profilu"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Ne možete da delite ovaj sadržaj pomoću ličnih aplikacija"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"IT administrator vam ne dozvoljava da delite ovaj sadržaj pomoću aplikacija na ličnom profilu"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Ne možete da otvorite ovaj sadržaj pomoću ličnih aplikacija"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"IT administrator vam ne dozvoljava da otvorite ovaj sadržaj pomoću aplikacija na ličnom profilu"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Profil za Work je pauziran"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Poslovni profil je pauziran"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Uključi"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Nijedna aplikacija za posao ne može da podržava ovaj sadržaj"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Nijedna aplikacija za posao ne može da otvori ovaj sadržaj"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 68c851c..0fc6572 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n•·уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n• уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"У рэжыме \"Эканомія трафіка\" фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Уключыць Эканомію трафіка?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Уключыць"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дыялогавае акно сілкавання"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"адпраўлены відарыс"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Размова"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групавая размова"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 85c18f4..579c80d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Служ. потр. профил: Включване"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личните ви приложения са блокирани, докато не включите служебния си потребителски профил"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Личните ви приложения ще бъдат блокирани утре"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Включване на служебния потребителски профил"</string>
<string name="me" msgid="6207584824693813140">"Аз"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции за таблета"</string>
@@ -1797,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n•·включва тъмната тема;\n•·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n• включва тъмната тема;\n• изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ще вкл. ли „Икономия на данни“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включване"</string>
@@ -2047,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалогов прозорец за захранването"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"изпратено изображение"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групов разговор"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"Над <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 41683e8..0505a3e 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1631,10 +1631,8 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে <xliff:g id="SERVICE">%1$s</xliff:g> চালু হয়ে যাবে। এটি একটি অ্যাক্সেসিবিলিটি ফিচার। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nসেটিংস > অ্যাক্সেসিবিলিটি থেকে আপনি এই শর্টকাট পরিবর্তন করতে পারবেন।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"চালু করুন"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"চালু করবেন না"</string>
- <!-- no translation found for accessibility_shortcut_menu_item_status_on (6608392117189732543) -->
- <skip />
- <!-- no translation found for accessibility_shortcut_menu_item_status_off (5531598275559472393) -->
- <skip />
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"চালু"</string>
+ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"বন্ধ"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> অ্যাপটিকে আপনার ডিভাইসে সম্পূর্ণ নিয়ন্ত্রণের অনুমতি দিতে চান?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> চালু করলে, ডেটা এনক্রিপশন উন্নত করার উদ্দেশ্যে আপনার ডিভাইস স্ক্রিন লক ব্যবহার করবে না।"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"যে অ্যাপগুলি আপনাকে অ্যাক্সেসিবিলিটির প্রয়োজন মেটাতে সাহায্য করে সেই অ্যাপগুলির জন্য সম্পূর্ণ নিয়ন্ত্রণের বিষয়টি উপযুক্ত, কিন্তু তা বলে সমস্ত অ্যাপের জন্য নয়।"</string>
@@ -1796,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n\n•গাঢ় থিম চালু করে\n•ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমিত করে\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n\n•গাঢ় থিম চালু করে\n•ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমিত করে"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"চালু করুন"</string>
@@ -2046,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাওয়ার ডায়লগ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"একটি ছবি পাঠানো হয়েছে"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"কথোপকথন"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গ্রুপ কথোপকথন"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 77991db..23b3cc0 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1819,10 +1819,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n•Uključuje Tamnu temu\n•Isključuje ili ograničava aktivnosti u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\"\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n•Uključuje Tamnu temu\n•Isključuje ili ograničava aktivnosti u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2080,15 +2078,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijaloški okvir za napajanje"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 64aa7f9..23863a5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1794,12 +1794,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\".\n\n"<annotation id="url">"Més informació"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Activar Economitzador de dades?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Activar l\'Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quadre de diàleg d\'engegada"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviat una imatge"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grup"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d1b0b5b..03f3691 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Spořič baterie za účelem úspory energie:\n\n• zapne tmavý motiv,\n• vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“\n\n"<annotation id="url">"Další informace"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Spořič baterie za účelem úspory energie:\n\n• zapne tmavý motiv,\n• vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogové okno k napájení"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"posílá obrázek"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzace"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzace"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3bb64cdc..916565f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n•Aktiverer Mørkt tema\n•Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n•Aktiverer Mørkt tema\n•Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivér"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks om strøm"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendte et billede"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 30cbf85..e5c269e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Der Energiesparmodus sorgt für eine längere Akkulaufzeit:\n\n• Das dunkle Design wird aktiviert\n• Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen wie \"Ok Google\" werden abgeschaltet oder eingeschränkt\n\n"<annotation id="url">"Weitere Informationen"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Der Energiesparmodus sorgt für eine längere Akkulaufzeit:\n\n• Das dunkle Design wird aktiviert\n• Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen wie \"Ok Google\" werden abgeschaltet oder eingeschränkt"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Der Datensparmodus verhindert zum einen, dass manche Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datensparmodus aktivieren?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivieren"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kleines Fenster für Akkustand"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sperrbildschirm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"hat ein Bild gesendet"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Unterhaltung"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppenunterhaltung"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2b4d6a7..6a2ceb3 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n\n•Ενεργοποιεί το Σκούρο θέμα\n•Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή Hey Google\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Για την επέκταση της διάρκειας ζωής της μπαταρίας, η Εξοικονόμηση μπαταρίας:\n\n•Ενεργοποιεί το Σκούρο θέμα\n•Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή Hey Google."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ενεργοποίηση"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Παράθυρο διαλόγου λειτουργίας συσκευής"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"έστειλε μια εικόνα"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Συνομιλία"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ομαδική συνομιλία"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index b20891d..9020dae 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Group conversation"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 91b0cab..51397c7 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Group conversation"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b20891d..9020dae 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Group conversation"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b20891d..9020dae 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialogue"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Group conversation"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index ed957de..9787079 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2042,8 +2042,9 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"On-screen Accessibility Shortcut"</string>
- <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"On-screen Accessibility Shortcut Chooser"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"On-screen Accessibility Shortcut"</string>
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"On-screen Accessibility Shortcut Chooser"</string>
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Accessibility Shortcut"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5afebbd..a7a0534 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para extender la duración de la batería, el Ahorro de batería hace lo siguiente:\n\n•Activa el Tema oscuro.\n•Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n\n•Activa el Tema oscuro.\n•Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Diálogo de encendido"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"envió una imagen"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversación"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversación en grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1288a13..a3a9f78 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -327,7 +327,7 @@
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos de huellas digitales"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Puede capturar los gestos realizados en el sensor de huellas digitales del dispositivo."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Hacer captura de pantalla"</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Hacer captura"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Puede hacer capturas de la pantalla."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"inhabilitar o modificar la barra de estado"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Permite que la aplicación inhabilite la barra de estado o añada y elimine iconos del sistema."</string>
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para que la batería dure más, Ahorro de batería:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para que la batería dure más, Ahorro de batería:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"El modo Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -1890,7 +1888,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anular pausa de aplicación"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar perfil de trabajo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Tus aplicaciones, notificaciones, datos y otras funciones del perfil de trabajo se activarán"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Abrir cuadro de diálogo"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviado una imagen"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversación"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversación de grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+ <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 196d834..ddb89af 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Lülitada andmemahu säästja sisse?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Energiasäästja dialoog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"saatis kujutise"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Vestlus"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupivestlus"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index b8810c5..26bbaa5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktibatu laneko profila"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplikazio pertsonalak blokeatuta egongo dira laneko profila aktibatzen duzun arte"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Aplikazio pertsonalak bihar blokeatuko dira"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Aktibatu laneko profila"</string>
<string name="me" msgid="6207584824693813140">"Ni"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string>
@@ -1797,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\".\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Une honetan erabiltzen ari zaren aplikazioak atzitu egin ahal izango ditu datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktibatu"</string>
@@ -2047,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Piztu edo itzaltzeko leihoa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantaila blokeatua"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pantaila-argazkia"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"erabiltzaileak irudi bat bidali du"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Elkarrizketa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Taldeko elkarrizketa"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 28254d9..f77d015 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -201,8 +201,8 @@
<string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"نمایه کاریتان را روشن کنید"</string>
- <string name="personal_apps_suspension_text" msgid="6115455688932935597">"تا زمانیکه نمایه کاریتان را روشن نکنید، برنامههای شخصیتان مسدود هستند"</string>
- <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"برنامههای شخصیتان فردا مسدود میشوند"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"تا زمانیکه نمایه کاریتان را روشن نکنید، برنامههای شخصیتان مسدودند"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"برنامههای شخصیتان فردا مسدود خواهند شد"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"روشن کردن نمایه کاری"</string>
<string name="me" msgid="6207584824693813140">"من"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"گزینههای رایانهٔ لوحی"</string>
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم بهروزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"برای افزایش عمر باتری، «بهینهسازی باتری»:\n\n•«طرح زمینه تیره» را روشن میکند\n•فعالیت پسزمینه، برخی جلوههای بصری، و دیگر ویژگیها مانند «Ok Google» را خاموش یا محدود میکند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"برای افزایش عمر باتری، «بهینهسازی باتری»:\n\n•«طرح زمینه تیره» را روشن میکند\n•فعالیت پسزمینه، برخی جلوههای بصری، و دیگر ویژگیها مانند «Ok Google» را خاموش یا محدود میکند"</string>
<string name="data_saver_description" msgid="4995164271550590517">"«صرفهجویی داده»، برای کمک به کاهش مصرف داده، از ارسال و دریافت داده در پسزمینه ازطرف بعضی برنامهها جلوگیری میکند. برنامهای که درحالحاضر استفاده میکنید میتواند به دادهها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تازمانیکه روی آنها ضربه نزنید نشان داده نمیشوند."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفهجویی داده» روشن شود؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"روشن کردن"</string>
@@ -1851,9 +1849,9 @@
<string name="stk_cc_ussd_to_dial" msgid="3139884150741157610">"درخواست USSD به تماس معمولی تغییر کرد"</string>
<string name="stk_cc_ussd_to_ss" msgid="4826846653052609738">"درخواست USSD بهدرخواست SS تغییر کرد"</string>
<string name="stk_cc_ussd_to_ussd" msgid="8343001461299302472">"به درخواست USSD جدید تغییر کرد"</string>
- <string name="stk_cc_ussd_to_dial_video" msgid="429118590323618623">"درخواست USSD به تماس ویدیویی تغییر کرد"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="429118590323618623">"درخواست USSD به تماس تصویری تغییر کرد"</string>
<string name="stk_cc_ss_to_dial" msgid="4087396658768717077">"درخواست SS به تماس معمولی تغییر کرد"</string>
- <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"درخواست SS به تماس ویدیویی تغییر کرد"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"درخواست SS به تماس تصویری تغییر کرد"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"درخواست SS به درخواست USSD تغییر کرد"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"به درخواست SS جدید تغییر کرد"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"نمایه کاری"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"کادر گفتگوی روشن/خاموش"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"نماگرفت"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"تصویری ارسال کرد"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"مکالمه"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"مکالمه گروهی"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e7f3a9b..9f50d77 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google)."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ota käyttöön"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Virran valintaikkuna"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"lähetti kuvan"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Keskustelu"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ryhmäkeskustelu"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9a6f186..2a9de66 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue sur l\'alimentation"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 75fc667..224dcfe 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -219,9 +219,9 @@
<string name="reboot_to_update_title" msgid="2125818841916373708">"Mise à jour du système Android"</string>
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"Préparation de la mise à jour en cours…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"Traitement du package de mise à jour…"</string>
- <string name="reboot_to_update_reboot" msgid="4474726009984452312">"Redémarrage en cours…"</string>
+ <string name="reboot_to_update_reboot" msgid="4474726009984452312">"Redémarrage…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"Rétablir la configuration d\'usine"</string>
- <string name="reboot_to_reset_message" msgid="3347690497972074356">"Redémarrage en cours…"</string>
+ <string name="reboot_to_reset_message" msgid="3347690497972074356">"Redémarrage…"</string>
<string name="shutdown_progress" msgid="5017145516412657345">"Arrêt en cours..."</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Votre tablette va s\'éteindre."</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Votre appareil Android TV va s\'éteindre."</string>
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n·• active le thème sombre\n·• désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Ok Google\"\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n·• active le thème sombre\n • désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue Marche/Arrêt"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g> ou +"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index a475b41..cfd555a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activa o perfil de traballo"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"As túas aplicacións persoais están bloqueadas ata que actives o teu perfil de traballo"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"As túas aplicacións persoais bloquearanse mañá"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Activar perfil de traballo"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string>
@@ -1797,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n•Activa o tema escuro\n•Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\"\n\n"<annotation id="url">"Máis información"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n•Activa o tema escuro\n•Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para contribuír a reducir o uso de datos, o aforro de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Queres activar o aforro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -2047,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Cadro de diálogo de acendido/apagado"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviouse unha imaxe"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"><xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index b6ea39a..cf7afb5 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n\n•ઘેરી થીમ ચાલુ કરે છે\n•બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “ઓકે Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n\n•ઘેરી થીમ ચાલુ કરે છે\n•બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “ઓકે Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ચાલુ કરો"</string>
@@ -1890,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ઍપ ફરી શરૂ કરો"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"કાર્યાલયની પ્રોફાઇલ ચાલુ કરીએ?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી કાર્યાલયની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય કાર્યાલયની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"ઑફિસ માટેની પ્રોફાઇલ ચાલુ કરીએ?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી ઑફિસ માટેની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય ઑફિસ માટેની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"પાવર સંવાદ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"છબી મોકલી"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"વાતચીત"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ગ્રૂપ વાતચીત"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6116c5a..5038d72 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है"</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा सेवर कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकता है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पावर डायलॉग खोलें"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"एक इमेज भेजी गई"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"बातचीत"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ग्रुप में बातचीत"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 811df8f..a458613 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Štednju podatkovnog prometa?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2078,15 +2076,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dijalog napajanja"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"šalje sliku"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 26f7584..f2e024d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által jelenleg használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bekapcsolás"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Akkumulátorral kapcsolatos párbeszédpanel"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"képet küldött"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Beszélgetés"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Csoportos beszélgetés"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index d7d00f2..bf7ec38 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Միացրեք աշխատանքային պորֆիլը"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Անձնական հավելվածներն արգելափակված կլինեն, մինչև չմիացնեք ձեր աշխատանքային պրոֆիլը"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Ձեր անձնական հավելվածները վաղը կարգելափակվեն"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Միացնել աշխատանքային պրոֆիլը"</string>
<string name="me" msgid="6207584824693813140">"Իմ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Պլանշետի ընտրանքները"</string>
@@ -1797,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «OK Google» հրահանգը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «OK Google» հրահանգը:"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի խնայումը:"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string>
@@ -2047,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Սնուցման պատուհան"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"օգտատերը պատկեր է ուղարկել"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Նամակագրություն"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Խմբային նամակագրություն"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 458df3b..c4ff2e3 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n\n•Mengaktifkan Tema gelap\n•Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n\n•Mengaktifkan Tema gelap\n•Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Aktifkan Penghemat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktifkan"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Daya"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"mengirim gambar"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Percakapan"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Percakapan Grup"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index fa03fba..168c630 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•Kveikir á dökku þema\n•Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“\n\n"<annotation id="url">"Frekari upplýsingar"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•Kveikir á dökku þema\n•Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan getur verið, svo dæmi sé tekið, að myndir eru ekki birtar fyrr en þú ýtir á þær."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Kveikja á gagnasparnaði?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Kveikja"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Gluggi til að slökkva/endurræsa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendi mynd"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtal"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Hópsamtal"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1ed81f1..f4794a2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il Tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il Tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Finestra di dialogo Alimentazione"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha inviato un\'immagine"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversazione"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversazione di gruppo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a6d538a..c1580da 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -204,12 +204,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"הפעלה של פרופיל העבודה שלך"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"האפליקציות שלך לשימוש אישי יהיו חסומות עד להפעלת פרופיל העבודה"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"האפליקציות שלך לשימוש אישי ייחסמו מחר"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"הפעלה של פרופיל העבודה"</string>
<string name="me" msgid="6207584824693813140">"אני"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"אפשרויות טאבלט"</string>
@@ -1678,10 +1675,8 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ניתן ללחוץ על שני מקשי עוצמת הקול למשך מספר שניות כדי להפעיל את <xliff:g id="SERVICE">%1$s</xliff:g>, תכונת נגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nאפשר לשנות את מקשי הקיצור האלה לתכונה נוספת ב\'הגדרות\' > \'נגישות\'."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"אני רוצה להפעיל"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"לא להפעיל"</string>
- <!-- no translation found for accessibility_shortcut_menu_item_status_on (6608392117189732543) -->
- <skip />
- <!-- no translation found for accessibility_shortcut_menu_item_status_off (5531598275559472393) -->
- <skip />
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"מופעל"</string>
+ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"כבוי"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"ברצונך להעניק לשירות <xliff:g id="SERVICE">%1$s</xliff:g> שליטה מלאה במכשיר?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"אם השירות <xliff:g id="SERVICE">%1$s</xliff:g> יופעל, המכשיר לא ישתמש בנעילת המסך כדי לשפר את הצפנת הנתונים."</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"שליטה מלאה מתאימה לאפליקציות שעוזרות עם צורכי הנגישות שלך, אבל לא לרוב האפליקציות."</string>
@@ -1845,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n•מפעילה עיצוב כהה\n•מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n•מפעילה עיצוב כהה\n•מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google"</string>
<string name="data_saver_description" msgid="4995164271550590517">"כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"הפעל"</string>
@@ -2117,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"תיבת דו-שיח לגבי הסוללה"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"נשלחה תמונה"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"שיחה"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"שיחה קבוצתית"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4695d24..1ba098f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n•ダークテーマをオンにする\n•バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n•ダークテーマをオンにする\n•バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string>
<string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータを送受信することはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ON にする"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源ダイアログ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"画像を送信しました"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"会話"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"グループの会話"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index ee4d116..f216680 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგველი:\n\n•ჩართავს ბნელ თემას\n•გამორთავს ან ზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგველი:\n\n•ჩართავს ბნელ თემას\n•გამორთავს ან ზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ჩაირთოს მონაცემთა დამზოგველი?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ჩართვა"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ელკვების დიალოგი"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"გაიგზავნა სურათი"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"მიმოწერა"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ჯგუფური მიმოწერა"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 29cce56..d905d46 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1306,9 +1306,9 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"Жалғанған құрылғы зарядталуда. Қосымша параметрлер үшін түртіңіз."</string>
<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_title" msgid="408390247354560331">"USB арқылы түзету қосылған"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"USB арқылы түзетуді өшіру үшін түртіңіз"</string>
- <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB түзетуін өшіру үшін таңдаңыз."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB арқылы түзетуді өшіру үшін таңдаңыз."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Сымсыз түзету байланыстырылды"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Сымсыз түзетуді өшіру үшін түртіңіз."</string>
<string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Сымсыз түзетуді өшіріңіз."</string>
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n\n•қараңғы тақырыпты іске қосады;\n•фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n\n•қараңғы тақырыпты іске қосады;\n•фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дерек шығынын азайту үшін Data Saver функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге және алуға жол бермейді. Ашық тұрған қолданба деректерді пайдаланады, бірақ шектеулі шамада (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Data Saver функциясын қосу керек пе?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Қосу"</string>
@@ -1891,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Толығырақ"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Қолданбаны қайта қосу"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Жұмыс профилі қосылсын ба?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Жұмыс қолданбалары, хабарландырулар, деректер және басқа да жұмыс профильдерінің мүмкіндіктері қосылады"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Жұмыс қолданбалары, хабарландырулар, деректер және жұмыс профилінің басқа да мүмкіндіктері қосылады."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
@@ -1924,7 +1922,7 @@
<string name="app_category_maps" msgid="6395725487922533156">"Карта және навигация"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Өнімділік"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Құрылғы жады"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB арқылы жөндеу"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB арқылы түзету"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"сағат"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"минут"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"Уақытты реттеу"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Қуат диалогтік терезесі"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сурет жіберілді"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтық чат"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 7f482bc..4ec4c14 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1796,10 +1796,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម កម្មវិធីសន្សំថ្ម៖\n\n•បើករចនាប័ទ្មងងឹត\n•បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Ok Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម កម្មវិធីសន្សំថ្ម៖\n\n•បើករចនាប័ទ្មងងឹត\n•បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Ok Google” ជាដើម"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"បើក"</string>
@@ -2046,15 +2044,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ប្រអប់ថាមពល"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"បានផ្ញើរូបភាព"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ការសន្ទនា"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ការសន្ទនាជាក្រុម"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c03f37e..5c80684 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n•ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n•ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n•ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n•ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ಆನ್ ಮಾಡಿ"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ಪವರ್ ಡೈಲಾಗ್"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ಸಂವಾದ"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ಗುಂಪು ಸಂವಾದ"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 66df055..79cd4fe 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2042,8 +2042,12 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"전원 대화상자"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
- <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"터치식 접근성 단축키"</string>
- <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"터치식 접근성 단축키 선택 도구"</string>
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
+ <skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e76ca63..9dc6e46 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батареянын мөөнөтүн узартуу үчүн, Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n\n•Караңгы теманы күйгүзөт\n•Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Батареянын иштешин узартуу үчүн, Батареяны үнөмдөөчү режим:\n\n•Караңгы теманы күйгүзөт\n•Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Трафикти үнөмдөө режиминде айрым колдонмолор дайын-даректерди фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайын-даректерди жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикти үнөмдөө режимин иштетесизби?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Күйгүзүү"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Кубат диалогу"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сүрөт жөнөттү"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Жазышуу"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтук маек"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index fbcae03..cd59760 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1308,7 +1308,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່ນັ້ນບໍ່ສາມາດໃຊ້ຮ່ວມກັບໂທລະສັບນີ້ໄດ້. ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"ເຊື່ອມຕໍ່ການດີບັກຜ່ານ USB ແລ້ວ"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"ແຕະເພື່ອປິດການດີບັກ USB"</string>
- <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ເລືອກເພື່ອປິດການດີບັກຜ່ານ USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ເຊື່ອມຕໍ່ການດີບັກໄຮ້ສາຍແລ້ວ"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"ແຕະເພື່ອປິດການດີບັກໄຮ້ສາຍ"</string>
<string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ເລືອກປິດການປິດການນຳໃຊ້ການດີບັກໄຮ້ສາຍ."</string>
@@ -1794,8 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Hey Google”\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Hey Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດອິນເຕີເນັດຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ເປີດຕົວປະຢັດອິນເຕີເນັດບໍ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ເປີດໃຊ້"</string>
@@ -1922,7 +1922,7 @@
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ຜະລິດຕະພາບ"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ບ່ອນຈັດເກັບຂໍ້ມູນອຸປະກອນ"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ການດີບັ໊ກຜ່ານ USB"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ການດີບັກຜ່ານ USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ຊົ່ວໂມງ"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"ນາທີ"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"ຕັ້ງເວລາ"</string>
@@ -2042,8 +2042,12 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ກ່ອງໂຕ້ຕອບການເປີດປິດ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
- <string name="accessibility_system_action_accessibility_button_label" msgid="5941347017132886642">"ທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
- <string name="accessibility_system_action_accessibility_button_chooser_label" msgid="6973618519666227981">"ຕົວເລືອກທາງລັດການຊ່ວຍເຂົ້າເຖິງຢູ່ໜ້າຈໍ"</string>
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
+ <skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 56483e0..e0132e4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Įj. Duomenų taupymo priemonę?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Įjungti"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Maitinimo dialogo langas"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"išsiuntė vaizdą"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pokalbis"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupės pokalbis"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 70056e8..eeaf12f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas darbības fonā, noteikti vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas darbības fonā, noteikti vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string>
@@ -2078,15 +2076,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Barošanas dialoglodziņš"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nosūtīts attēls"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Saruna"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupas saruna"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-mcc334-mnc020/config.xml b/core/res/res/values-mcc334-mnc020/config.xml
index 0970517..c64acc7 100644
--- a/core/res/res/values-mcc334-mnc020/config.xml
+++ b/core/res/res/values-mcc334-mnc020/config.xml
@@ -18,4 +18,7 @@
-->
<resources>
<bool name="config_use_sim_language_file">false</bool>
+
+ <bool name="config_pdp_rejeect_enable_retry">true</bool>
+ <integer name="config_pdp_reject_retry_delay_ms">45000</integer>
</resources>
\ No newline at end of file
diff --git a/core/res/res/values-mcc334-mnc020/strings.xml b/core/res/res/values-mcc334-mnc020/strings.xml
new file mode 100644
index 0000000..a8a78d5
--- /dev/null
+++ b/core/res/res/values-mcc334-mnc020/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="config_pdp_reject_dialog_title"></string>
+ <string name="config_pdp_reject_user_authentication_failed">AUTHENTICATION FAILURE -29-</string>
+ <string name="config_pdp_reject_service_not_subscribed">NOT SUBSCRIBED TO SERVICE -33-</string>
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed">Multiple PDN connections for a given APN not allowed -55-</string>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 51501b4..7c0cff1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Вклучете го работниот профил"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Вашите лични апликации се блокирани додека да го вклучите работниот профил"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Вашите лични апликации ќе се блокираат утре"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Вклучи го работниот профил"</string>
<string name="me" msgid="6207584824693813140">"Јас"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции на таблет"</string>
@@ -1799,10 +1796,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n•вклучува темна тема;\n•исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Ok Google“.\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n•вклучува темна тема;\n•исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Одредена апликација што ја користите ќе може да користи интернет, но можеби тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажуваат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Да се вклучи „Штедач на интернет“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Вклучи"</string>
@@ -2049,15 +2044,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог за напојување"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"испрати слика"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групен разговор"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 791117c..bd1193e 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n\n•ഡാർക്ക് തീം ഓണാക്കും\n•പശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n\n•ഡാർക്ക് തീം ഓണാക്കും\n•പശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ഓണാക്കുക"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"പവർ ഡയലോഗ്"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്ക്രീൻ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ചിത്രം അയച്ചു"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"സംഭാഷണം"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ഗ്രൂപ്പ് സംഭാഷണം"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f7ac069..51138a7 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч:\n\n•Бараан загварыг асаана\n•Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарлана\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч:\n\n•Бараан загварыг асаана\n•Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарлана"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь ар талд ажиллаж буй зарим апп-н өгөгдлийг илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Энэ нь жишээлбэл зургийг товших хүртэл харагдахгүй гэсэн үг юм."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Дата хэмнэгчийг асаах уу?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Асаах"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Тэжээлийн харилцах цонх"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"зураг илгээсэн"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Харилцан яриа"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Бүлгийн харилцан яриа"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d842abd..7943bd4 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1794,13 +1794,11 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर चालू करायचे?"</string>
- <string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करा"</string>
+ <string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
<item quantity="one">एका मिनिटासाठी (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> पर्यंत)</item>
@@ -1890,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"अॅप उघडा"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल चालू ठेवायची?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये चालू केली जातील"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल सुरू ठेवायची?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये सुरू केली जातील"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पॉवर डायलॉग"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"इमेज पाठवली आहे"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"संभाषण"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"गट संभाषण"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2364c0a..23808b8 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n•Menghidupkan Tema gelap\n•Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Ok Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n•Menghidupkan Tema gelap\n•Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Kuasa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"menghantar imej"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Perbualan"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Perbualan Kumpulan"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 17b7c7c..f8e409d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က- \n\n•မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n•နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က- \n\n•မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n•နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ဖွင့်ပါ"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ပါဝါ ဒိုင်ယာလော့"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ပုံပို့ထားသည်"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"စကားဝိုင်း"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"အဖွဲ့စကားဝိုင်း"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 5b7787f..f4b7ec3b 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slå på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slår på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du slå på Datasparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Slå på"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogboks for å slå av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har sendt et bilde"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index c592c75..ba599e84 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1800,10 +1800,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ\n\n"<annotation id="url">"थप जान्नुहोस्"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाको प्रयोगलाई कम गर्न डेटा सर्भरले केही अनुप्रयोगलाई पृष्ठभूमिमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले हाल प्रयोग गरिरहनुभएको अनु्प्रयोगले डेटा चलाउन सक्छ, तर पहिला भन्दा कम अन्तरालमा मात्र। उदाहरणका लागि, तपाईले छविहरूमा ट्याप नगरेसम्म ती छविहरू देखिँदैनन्।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेभर सक्रिय गर्ने हो?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सक्रिय गर्नुहोस्"</string>
@@ -2050,15 +2048,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पावर संवाद"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"छवि पठाइयो"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"वार्तालाप"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"सामूहिक वार्तालाप"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f834ade..f320e5d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n•Het donkere thema aanzetten\n•Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitzetten of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n•Het donkere thema aanzetten\n•Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitzetten of beperken"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Inschakelen"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Voedingsdialoogvenster"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"heeft een afbeelding gestuurd"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Gesprek"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Groepsgesprek"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 24b4e2e..28f552e 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1631,10 +1631,8 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଏକ ଆକ୍ସେସିବିଲିଟୀ ଫିଚର୍ <xliff:g id="SERVICE">%1$s</xliff:g> ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nଆପଣ ସେଟିଂସ୍ &gt ଆକ୍ସେସିବିଲିଟୀରେ ଏହି ସର୍ଚକଟକୁ ଅନ୍ୟ ଏକ ଫିଚରରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"ଚାଲୁ କରନ୍ତୁ ନାହିଁ"</string>
- <!-- no translation found for accessibility_shortcut_menu_item_status_on (6608392117189732543) -->
- <skip />
- <!-- no translation found for accessibility_shortcut_menu_item_status_off (5531598275559472393) -->
- <skip />
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ଚାଲୁ ଅଛି"</string>
+ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"ବନ୍ଦ ଅଛି"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g>କୁ ଆପଣଙ୍କ ଡିଭାଇସର ସମ୍ପୂର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣର ଅନୁମତି ଦେବେ?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"ଯଦି ଆପଣ <xliff:g id="SERVICE">%1$s</xliff:g> ଚାଲୁ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଡାଟା ଏନକ୍ରିପ୍ସନ୍ ବୃଦ୍ଧି କରିବାକୁ ଆପଣଙ୍କର ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରିବ ନାହିଁ।"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"ଯେଉଁ ଆପ୍ସ ଆପଣଙ୍କୁ ଆକ୍ସେସିବିଲିଟୀ ଆବଶ୍ୟକତାରେ ସହାୟତା କରେ, ସେହି ଆପ୍ସ ପାଇଁ ସମ୍ପୂର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ ଉପଯୁକ୍ତ ଅଟେ, କିନ୍ତୁ ଅଧିକାଂଶ ଆପ୍ସ ପାଇଁ ଉପଯୁକ୍ତ ନୁହେଁ।"</string>
@@ -1796,13 +1794,11 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍ ଅପଡେଟ୍ କରିଛନ୍ତି"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍ ଡିଲିଟ୍ କରିଛନ୍ତି"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ\n\n"<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଇମେଜ୍ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍ ଚାଲୁ କରିବେ?"</string>
- <string name="data_saver_enable_button" msgid="4399405762586419726">"ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="data_saver_enable_button" msgid="4399405762586419726">"ଚାଲୁ କରନ୍ତୁ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">%1$d ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
<item quantity="one">ଏକ ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
@@ -1892,9 +1888,9 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ଆପ୍ ଅନପଜ୍ କରନ୍ତୁ"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ଚାଲୁ କରିବେ?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"ଆପଣଙ୍କର କାର୍ଯ୍ୟକାରୀ ଆପ୍, ବିଜ୍ଞପ୍ତି, ଡାଟା ଓ ଅନ୍ୟ ୱର୍କ ପ୍ରୋଫାଇଲ୍ଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ"</string>
- <string name="work_mode_turn_on" msgid="3662561662475962285">"ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍କୁ ଚାଲୁ କରିବେ?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"ଆପଣଙ୍କର କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍, ବିଜ୍ଞପ୍ତି, ଡାଟା ଓ ଅନ୍ୟ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ"</string>
+ <string name="work_mode_turn_on" msgid="3662561662475962285">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ଏହି ଆପ୍କୁ Androidର ପୁରୁଣା ଭର୍ସନ୍ ପାଇଁ ନିର୍ମାଣ କରାଯାଇଥିଲା ଏବଂ ଠିକ୍ ଭାବେ କାମ କରିନପାରେ। ଏହାପାଇଁ ଅପଡେଟ୍ ଅଛି କି ନାହିଁ ଯାଞ୍ଚ କରନ୍ତୁ କିମ୍ବା ଡେଭେଲପର୍ଙ୍କ ସହିତ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
@@ -2046,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ପାୱାର ଡାୟଲଗ୍ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ବାର୍ତ୍ତାଳାପ"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ଗୋଷ୍ଠୀ ବାର୍ତ୍ତାଳାପ"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 893719e..e0c6056 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n•ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n•ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n•ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n•ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ਚਾਲੂ ਕਰੋ"</string>
@@ -1890,8 +1888,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਐਪ ਫਿਲਹਾਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਇਸਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ਹੋਰ ਜਾਣੋ"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ਐਪ ਤੋਂ ਰੋਕ ਹਟਾਓ"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"ਕੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰਨੀ ਹੈ?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"ਤੁਹਾਡੀਆਂ ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ, ਸੂਚਨਾਵਾਂ, ਡਾਟਾ ਅਤੇ ਹੋਰ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"ਕੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"ਤੁਹਾਡੀਆਂ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ, ਸੂਚਨਾਵਾਂ, ਡਾਟਾ ਅਤੇ ਹੋਰ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ਪਾਵਰ ਵਿੰਡੋ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ਗੱਲਬਾਤ"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ਗੁਰੱਪ ਗੱਲਬਾਤ"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index eee3dc6..c12c9ae 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n•włącza tryb ciemny,\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n•włącza tryb ciemny,\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Okno opcji zasilania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"wysłano obraz"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Rozmowa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Rozmowa grupowa"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8c37b5e..dbd69a1 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+ <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a1c8f6b..6bd1dfa 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -185,7 +185,7 @@
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo gestor do seu perfil de trabalho"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="work_profile_deleted" msgid="5891181538182009328">"Perfil de trabalho eliminado"</string>
- <string name="work_profile_deleted_details" msgid="3773706828364418016">"A aplicação de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
+ <string name="work_profile_deleted_details" msgid="3773706828364418016">"A app de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O seu perfil de trabalho já não está disponível neste dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiadas tentativas de introdução da palavra-passe"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"O administrador anulou o dispositivo para utilização pessoal."</string>
@@ -198,7 +198,7 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string>
- <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a aplicação de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string>
+ <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a app de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ative o perfil de trabalho"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"As suas apps pessoais estão bloqueadas até ativar o seu perfil de trabalho."</string>
@@ -285,7 +285,7 @@
<string name="notification_channel_usb" msgid="1528280969406244896">"Ligação USB"</string>
<string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplicação em execução"</string>
<string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplicações que estão a consumir bateria"</string>
- <string name="foreground_service_app_in_background" msgid="1439289699671273555">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> está a consumir bateria."</string>
+ <string name="foreground_service_app_in_background" msgid="1439289699671273555">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a consumir bateria."</string>
<string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicações estão a consumir bateria."</string>
<string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
@@ -330,97 +330,97 @@
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Tirar captura de ecrã"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"É possível tirar uma captura de ecrã."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"desativar ou modificar barra de estado"</string>
- <string name="permdesc_statusBar" msgid="5809162768651019642">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
+ <string name="permdesc_statusBar" msgid="5809162768651019642">"Permite à app desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="2523421018081437981">"ser apresentada na barra de estado"</string>
- <string name="permdesc_statusBarService" msgid="6652917399085712557">"Permite que a aplicação seja apresentada na barra de estado."</string>
+ <string name="permdesc_statusBarService" msgid="6652917399085712557">"Permite que a app seja apresentada na barra de estado."</string>
<string name="permlab_expandStatusBar" msgid="1184232794782141698">"expandir/fechar barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permite à aplicação expandir ou fechar a barra de estado."</string>
+ <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permite à app expandir ou fechar a barra de estado."</string>
<string name="permlab_install_shortcut" msgid="7451554307502256221">"instalar atalhos"</string>
- <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permite que uma aplicação adicione atalhos ao Ecrã principal sem a intervenção do utilizador."</string>
+ <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permite que uma app adicione atalhos ao Ecrã principal sem a intervenção do utilizador."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"desinstalar atalhos"</string>
- <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite que a aplicação remova atalhos do Ecrã principal sem a intervenção do utilizador."</string>
+ <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite que a app remova atalhos do Ecrã principal sem a intervenção do utilizador."</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"redirecionar as chamadas efetuadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permite que a aplicação veja o número que é marcado durante uma chamada efetuada, com a opção de redirecionar a chamada para um número diferente ou terminar a chamada."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Permite que a app veja o número que é marcado durante uma chamada efetuada, com a opção de redirecionar a chamada para um número diferente ou terminar a chamada."</string>
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"atender chamadas telefónicas"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que a aplicação atenda chamadas recebidas."</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite que a app atenda chamadas recebidas."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"receber mensagens de texto (SMS)"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite que a aplicação receba e processe mensagens SMS. Isto significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite que a app receba e processe mensagens SMS. Isto significa que a app poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"receber mensagens de texto (MMS)"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"Permite que a aplicação receba e processe mensagens MMS. Isto significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"Permite que a app receba e processe mensagens MMS. Isto significa que a app poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"Encaminhar mensagens de difusão celular"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a aplicação se vincule ao módulo de difusão celular para encaminhar mensagens de difusão celular à medida que são recebidas. Os alertas de difusão celular são fornecidos em algumas localizações para avisar sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma difusão celular de emergência."</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a app se vincule ao módulo de difusão celular para encaminhar mensagens de difusão celular à medida que são recebidas. Os alertas de difusão celular são fornecidos em algumas localizações para avisar sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma difusão celular de emergência."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de transmissão celular"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que a aplicação leia mensagens de transmissão celular recebidas pelo seu dispositivo. Os alertas de transmissão celular são fornecidos em algumas localizações para avisá-lo sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma transmissão celular de emergência."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que a app leia mensagens de transmissão celular recebidas pelo seu dispositivo. Os alertas de transmissão celular são fornecidos em algumas localizações para avisá-lo sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma transmissão celular de emergência."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds subscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Permite à aplicação obter detalhes acerca dos feeds atualmente sincronizados."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Permite à app obter detalhes acerca dos feeds atualmente sincronizados."</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"enviar e ver mensagens SMS"</string>
- <string name="permdesc_sendSms" msgid="6757089798435130769">"Permite que a aplicação envie mensagens SMS. Isto pode resultar em custos inesperados. As aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
+ <string name="permdesc_sendSms" msgid="6757089798435130769">"Permite que a app envie mensagens SMS. Isto pode resultar em custos inesperados. As aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
<string name="permlab_readSms" msgid="5164176626258800297">"ler as mensagens de texto (SMS ou MMS)"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Esta aplicação pode ler todas as mensagens SMS (de texto) armazenadas no seu tablet."</string>
- <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Esta aplicação pode ler todas as mensagens SMS (de texto) armazenadas no seu dispositivo Android TV."</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Esta aplicação pode ler todas as mensagens SMS (de texto) armazenadas no seu telemóvel."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Esta app pode ler todas as mensagens SMS (de texto) armazenadas no seu tablet."</string>
+ <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Esta app pode ler todas as mensagens SMS (de texto) armazenadas no seu dispositivo Android TV."</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Esta app pode ler todas as mensagens SMS (de texto) armazenadas no seu telemóvel."</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"receber mensagens de texto (WAP)"</string>
- <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permite que a aplicação receba e processe mensagens WAP. Esta autorização inclui a capacidade de monitorizar ou eliminar mensagens enviadas para si sem as apresentar."</string>
+ <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permite que a app receba e processe mensagens WAP. Esta autorização inclui a capacidade de monitorizar ou eliminar mensagens enviadas para si sem as apresentar."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"obter aplicações em execução"</string>
- <string name="permdesc_getTasks" msgid="7388138607018233726">"Permite que a aplicação recupere informações acerca de tarefas executadas atual e recentemente. Isto pode permitir que a aplicação descubra informações acerca de quais as aplicações utilizadas no dispositivo."</string>
+ <string name="permdesc_getTasks" msgid="7388138607018233726">"Permite que a app recupere informações acerca de tarefas executadas atual e recentemente. Isto pode permitir que a app descubra informações acerca de quais as aplicações utilizadas no dispositivo."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"gerir proprietários de perfis e de dispositivos"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"Permite que as aplicações definam proprietários de perfis e o proprietário do dispositivo."</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"reordenar as aplicações em execução"</string>
- <string name="permdesc_reorderTasks" msgid="8796089937352344183">"Permite que a aplicação mova tarefas para primeiro e segundo plano. A aplicação poderá fazê-lo sem qualquer entrada do utilizador."</string>
+ <string name="permdesc_reorderTasks" msgid="8796089937352344183">"Permite que a app mova tarefas para primeiro e segundo plano. A app poderá fazê-lo sem qualquer entrada do utilizador."</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"ativar modo de carro"</string>
- <string name="permdesc_enableCarMode" msgid="56419168820473508">"Permite que a aplicação ative o modo automóvel."</string>
+ <string name="permdesc_enableCarMode" msgid="56419168820473508">"Permite que a app ative o modo automóvel."</string>
<string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"fechar outras aplicações"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"Permite que a aplicação termine processos em segundo plano de outras aplicações. Isto pode fazer com que outras aplicações deixem de funcionar."</string>
- <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Esta aplicação pode aparecer por cima de outras aplicações"</string>
- <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Esta aplicação pode aparecer por cima de outras aplicações ou de outras partes do ecrã. Tal pode interferir com a utilização normal das aplicações e alterar a forma como as outras aplicações aparecem."</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"Permite que a app termine processos em segundo plano de outras aplicações. Isto pode fazer com que outras aplicações deixem de funcionar."</string>
+ <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Esta app pode aparecer por cima de outras aplicações"</string>
+ <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Esta app pode aparecer por cima de outras aplicações ou de outras partes do ecrã. Tal pode interferir com a utilização normal das aplicações e alterar a forma como as outras aplicações aparecem."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"executar em segundo plano"</string>
- <string name="permdesc_runInBackground" msgid="4344539472115495141">"Esta aplicação pode ser executada em segundo plano, o que pode descarregar a bateria mais rapidamente."</string>
+ <string name="permdesc_runInBackground" msgid="4344539472115495141">"Esta app pode ser executada em segundo plano, o que pode descarregar a bateria mais rapidamente."</string>
<string name="permlab_useDataInBackground" msgid="783415807623038947">"utilizar dados em segundo plano"</string>
- <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Esta aplicação pode utilizar dados em segundo plano, o que pode aumentar a utilização de dados."</string>
- <string name="permlab_persistentActivity" msgid="464970041740567970">"fazer com que a aplicação seja sempre executada"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Permite que a aplicação torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o tablet mais lento."</string>
- <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Permite que a aplicação torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o seu dispositivo Android TV mais lento."</string>
- <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que a aplicação torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o telemóvel mais lento."</string>
+ <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Esta app pode utilizar dados em segundo plano, o que pode aumentar a utilização de dados."</string>
+ <string name="permlab_persistentActivity" msgid="464970041740567970">"fazer com que a app seja sempre executada"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Permite que a app torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o tablet mais lento."</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Permite que a app torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o seu dispositivo Android TV mais lento."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que a app torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o telemóvel mais lento."</string>
<string name="permlab_foregroundService" msgid="1768855976818467491">"executar serviço em primeiro plano"</string>
- <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que a aplicação utilize serviços em primeiro plano."</string>
- <string name="permlab_getPackageSize" msgid="375391550792886641">"medir espaço de armazenamento da aplicação"</string>
- <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite à aplicação obter o código, os dados e o tamanhos de cache da mesma"</string>
+ <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que a app utilize serviços em primeiro plano."</string>
+ <string name="permlab_getPackageSize" msgid="375391550792886641">"medir espaço de armazenamento da app"</string>
+ <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite à app obter o código, os dados e o tamanhos de cache da mesma"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"modificar as definições do sistema"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permite à aplicação modificar os dados das definições do sistema. As aplicações maliciosas podem corromper a configuração do seu sistema."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permite à app modificar os dados das definições do sistema. As aplicações maliciosas podem corromper a configuração do seu sistema."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"executar no arranque"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode atrasar o arranque do tablet e permitir à aplicação abrandar todo o funcionamento do tablet, uma vez que está em constante execução."</string>
- <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Permite à aplicação iniciar-se automaticamente assim que o arranque do sistema tiver terminado. Isto pode atrasar o arranque do seu dispositivo Android TV e permitir à aplicação abrandar todo o funcionamento do dispositivo, uma vez que está em constante execução."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode atrasar o arranque do telemóvel e permitir à aplicação abrandar todo o funcionamento do telemóvel, uma vez que está em constante execução."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Permite que uma app se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode atrasar o arranque do tablet e permitir à app abrandar todo o funcionamento do tablet, uma vez que está em constante execução."</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Permite à app iniciar-se automaticamente assim que o arranque do sistema tiver terminado. Isto pode atrasar o arranque do seu dispositivo Android TV e permitir à app abrandar todo o funcionamento do dispositivo, uma vez que está em constante execução."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"Permite que uma app se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode atrasar o arranque do telemóvel e permitir à app abrandar todo o funcionamento do telemóvel, uma vez que está em constante execução."</string>
<string name="permlab_broadcastSticky" msgid="4552241916400572230">"enviar difusão fixa"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"Permite que uma aplicação envie difusões fixas, que permanecem após o fim da difusão. Uma utilização excessiva pode tornar o tablet lento ou instável, fazendo com que utilize demasiada memória."</string>
- <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Permite à aplicação enviar transmissões fixas que permanecem após o fim da transmissão. Uma utilização excessiva pode tornar o seu dispositivo Android TV lento ou instável, fazendo com que utilize demasiada memória."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Permite que a aplicação envie difusões fixas, que permanecem após o fim da difusão. Uma utilização excessiva pode tornar o telemóvel lento ou instável, fazendo com que utilize demasiada memória."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"Permite que uma app envie difusões fixas, que permanecem após o fim da difusão. Uma utilização excessiva pode tornar o tablet lento ou instável, fazendo com que utilize demasiada memória."</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Permite à app enviar transmissões fixas que permanecem após o fim da transmissão. Uma utilização excessiva pode tornar o seu dispositivo Android TV lento ou instável, fazendo com que utilize demasiada memória."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Permite que a app envie difusões fixas, que permanecem após o fim da difusão. Uma utilização excessiva pode tornar o telemóvel lento ou instável, fazendo com que utilize demasiada memória."</string>
<string name="permlab_readContacts" msgid="8776395111787429099">"ler os contactos"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permite à aplicação ler dados acerca dos contactos armazenados no seu tablet. As aplicações também terão acesso às contas no tablet que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
- <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permite à aplicação ler dados acerca dos contactos armazenados no seu dispositivo Android TV. As aplicações terão acesso às contas no dispositivo Android TV que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
- <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permite à aplicação ler dados acerca dos contactos armazenados no seu telemóvel. As aplicações também terão acesso às contas no telemóvel que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permite à app ler dados acerca dos contactos armazenados no seu tablet. As aplicações também terão acesso às contas no tablet que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permite à app ler dados acerca dos contactos armazenados no seu dispositivo Android TV. As aplicações terão acesso às contas no dispositivo Android TV que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
+ <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permite à app ler dados acerca dos contactos armazenados no seu telemóvel. As aplicações também terão acesso às contas no telemóvel que criaram contactos. Pode incluir contas criadas pelas aplicações instaladas. Esta autorização permite às aplicações guardarem dados de contactos e as aplicações maliciosas podem partilhá-los sem o seu conhecimento."</string>
<string name="permlab_writeContacts" msgid="8919430536404830430">"modificar os contactos"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Permite que a aplicação modifique dados acerca dos contactos armazenados no tablet. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
- <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permite à aplicação modificar dados acerca dos contactos armazenados no seu dispositivo Android TV. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
- <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permite que a aplicação modifique dados acerca dos contactos guardados no telemóvel. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Permite que a app modifique dados acerca dos contactos armazenados no tablet. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permite à app modificar dados acerca dos contactos armazenados no seu dispositivo Android TV. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"Permite que a app modifique dados acerca dos contactos guardados no telemóvel. Esta autorização permite que as aplicações eliminem dados de contactos."</string>
<string name="permlab_readCallLog" msgid="1739990210293505948">"ler registo de chamadas"</string>
- <string name="permdesc_readCallLog" msgid="8964770895425873433">"Esta aplicação pode ler o seu histórico de chamadas."</string>
+ <string name="permdesc_readCallLog" msgid="8964770895425873433">"Esta app pode ler o seu histórico de chamadas."</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"escrever registo de chamadas"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permite à aplicação modificar o registo de chamadas do tablet, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
- <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permite à aplicação modificar o registo de chamadas do seu dispositivo Android TV, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permite à aplicação modificar o registo de chamadas do telemóvel, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permite à app modificar o registo de chamadas do tablet, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permite à app modificar o registo de chamadas do seu dispositivo Android TV, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permite à app modificar o registo de chamadas do telemóvel, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
<string name="permlab_bodySensors" msgid="3411035315357380862">"aceder a sensores corporais (como monitores do ritmo cardíaco)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Permite que a aplicação aceda a dados de sensores que monitorizam a sua condição física, como o ritmo cardíaco."</string>
+ <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Permite que a app aceda a dados de sensores que monitorizam a sua condição física, como o ritmo cardíaco."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"Ler detalhes e eventos do calendário"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Esta aplicação pode ler todos os eventos do calendário armazenados no seu tablet e partilhar ou guardar os dados do calendário."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Esta aplicação pode ler todos os eventos do calendário armazenados no seu dispositivo Android TV e partilhar ou guardar os dados do calendário."</string>
- <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Esta aplicação pode ler todos os eventos do calendário armazenados no seu telemóvel e partilhar ou guardar os dados do calendário."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Esta app pode ler todos os eventos do calendário armazenados no seu tablet e partilhar ou guardar os dados do calendário."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Esta app pode ler todos os eventos do calendário armazenados no seu dispositivo Android TV e partilhar ou guardar os dados do calendário."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Esta app pode ler todos os eventos do calendário armazenados no seu telemóvel e partilhar ou guardar os dados do calendário."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"adicionar ou modificar eventos do calendário e enviar email a convidados sem o conhecimento dos proprietários"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Esta aplicação pode adicionar, remover ou alterar eventos do calendário no seu tablet. Esta aplicação pode enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Esta aplicação pode adicionar, remover ou alterar eventos do calendário no seu dispositivo Android TV. Pode também enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Esta aplicação pode adicionar, remover ou alterar eventos do calendário no seu telemóvel. Esta aplicação pode enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Esta app pode adicionar, remover ou alterar eventos do calendário no seu tablet. Esta app pode enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Esta app pode adicionar, remover ou alterar eventos do calendário no seu dispositivo Android TV. Pode também enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Esta app pode adicionar, remover ou alterar eventos do calendário no seu telemóvel. Esta app pode enviar mensagens que parecem vir de proprietários do calendário ou alterar eventos sem notificar os respetivos proprietários."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"aceder a comandos adicionais do fornecedor de localização"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Permite que a aplicação aceda a comandos adicionais do fornecedor de localização. Esta opção pode permitir que a aplicação interfira com o funcionamento do GPS ou de outras fontes de localização."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Permite que a app aceda a comandos adicionais do fornecedor de localização. Esta opção pode permitir que a app interfira com o funcionamento do GPS ou de outras fontes de localização."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"apenas aceder à localização exata em primeiro plano"</string>
<string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Esta app pode obter a sua localização exata a partir dos Serviços de localização enquanto a app está a ser utilizada. Os Serviços de localização para o dispositivo têm de estar ativados para a app obter a localização. Isto pode aumentar a utilização da bateria."</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"apenas aceder à localização aproximada em primeiro plano"</string>
@@ -428,114 +428,114 @@
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"aceder à localização em segundo plano"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Esta app pode aceder à localização em qualquer altura, mesmo quando a app não está a ser utilizada."</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas definições de áudio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que a aplicação modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que a app modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta aplicação pode gravar áudio através do microfone em qualquer altura."</string>
+ <string name="permdesc_recordAudio" msgid="3976213377904701093">"Esta app pode gravar áudio através do microfone em qualquer altura."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o SIM"</string>
- <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que a aplicação envie comandos para o SIM. Esta ação é muito perigosa."</string>
+ <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que a app envie comandos para o SIM. Esta ação é muito perigosa."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer a atividade física"</string>
- <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta aplicação consegue reconhecer a sua atividade física."</string>
+ <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta app consegue reconhecer a sua atividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e vídeos"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"Esta aplicação pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>
- <string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que uma aplicação ou um serviço aceda às câmaras do sistema para tirar fotos e vídeos"</string>
+ <string name="permdesc_camera" msgid="1354600178048761499">"Esta app pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>
+ <string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que uma app ou um serviço aceda às câmaras do sistema para tirar fotos e vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app do sistema ou privilegiada pode tirar fotos e gravar vídeos através de uma câmara do sistema em qualquer altura. Também necessita da autorização android.permission.CAMERA para a app."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que uma app ou um serviço receba chamadas de retorno sobre dispositivos de câmara que estão a ser abertos ou fechados"</string>
- <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta app pode receber chamadas de retorno quando qualquer dispositivo de câmara está a ser aberto (e por que aplicação) ou fechado."</string>
+ <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta app pode receber chamadas de retorno quando qualquer dispositivo de câmara está a ser aberto (e por que app) ou fechado."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar vibração"</string>
- <string name="permdesc_vibrate" msgid="8733343234582083721">"Permite à aplicação controlar o vibrador."</string>
+ <string name="permdesc_vibrate" msgid="8733343234582083721">"Permite à app controlar o vibrador."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que a app aceda ao estado de vibração."</string>
<string name="permlab_callPhone" msgid="1798582257194643320">"marcar números de telefone diretamente"</string>
- <string name="permdesc_callPhone" msgid="5439809516131609109">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
+ <string name="permdesc_callPhone" msgid="5439809516131609109">"Permite que a app ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a app ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"aceder ao serviço de chamadas IMS"</string>
- <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permite que a aplicação utilize o serviço IMS para fazer chamadas sem a sua intervenção."</string>
+ <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permite que a app utilize o serviço IMS para fazer chamadas sem a sua intervenção."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"ler o estado e a identidade do telemóvel"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Permite que a app aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a app determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"encaminhar chamadas através do sistema"</string>
- <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Permite que a aplicação encaminhe as respetivas chamadas através do sistema de modo a melhorar a experiência da chamada."</string>
+ <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Permite que a app encaminhe as respetivas chamadas através do sistema de modo a melhorar a experiência da chamada."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"ver e controlar chamadas através do sistema."</string>
- <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Permite à aplicação ver e controlar as chamadas em curso no dispositivo. Isto inclui informações como números de telefone das chamadas e o estado das mesmas."</string>
+ <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Permite à app ver e controlar as chamadas em curso no dispositivo. Isto inclui informações como números de telefone das chamadas e o estado das mesmas."</string>
<string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"isenta de restrições de gravação de áudio"</string>
<string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Isente a app de restrições para gravar áudio."</string>
- <string name="permlab_acceptHandover" msgid="2925523073573116523">"continuar uma chamada a partir de outra aplicação"</string>
- <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite à aplicação continuar uma chamada iniciada noutra aplicação."</string>
+ <string name="permlab_acceptHandover" msgid="2925523073573116523">"continuar uma chamada a partir de outra app"</string>
+ <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite à app continuar uma chamada iniciada noutra app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ler os números de telefone"</string>
- <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite à aplicação aceder aos números de telefone do dispositivo."</string>
+ <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite à app aceder aos números de telefone do dispositivo."</string>
<string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"manter o ecrã do automóvel ligado"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"impedir que o tablet entre em inactividade"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"impedir o seu dispositivo Android TV de entrar no modo de suspensão"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir modo de inactividade do telefone"</string>
<string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que a app mantenha o ecrã do automóvel ligado."</string>
- <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
- <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que a aplicação impeça o seu dispositivo Android TV de entrar no modo de suspensão."</string>
- <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que a aplicação impeça o telemóvel de entrar em inatividade."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que a app impeça o tablet de entrar no modo de suspensão."</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que a app impeça o seu dispositivo Android TV de entrar no modo de suspensão."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que a app impeça o telemóvel de entrar em inatividade."</string>
<string name="permlab_transmitIr" msgid="8077196086358004010">"transmitir infravermelhos"</string>
- <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permite que a aplicação utilize o transmissor de infravermelhos do tablet."</string>
- <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permite que a aplicação utilize o transmissor de infravermelhos do seu dispositivo Android TV."</string>
- <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permite que a aplicação utilize o transmissor de infravermelhos do telemóvel."</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permite que a app utilize o transmissor de infravermelhos do tablet."</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permite que a app utilize o transmissor de infravermelhos do seu dispositivo Android TV."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permite que a app utilize o transmissor de infravermelhos do telemóvel."</string>
<string name="permlab_setWallpaper" msgid="6959514622698794511">"definir imagem de fundo"</string>
- <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permite à aplicação definir a imagem de fundo do sistema."</string>
+ <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permite à app definir a imagem de fundo do sistema."</string>
<string name="permlab_setWallpaperHints" msgid="1153485176642032714">"ajustar o tamanho da imagem de fundo"</string>
- <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Permite que a aplicação defina as sugestões de tamanho da imagem de fundo do sistema."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Permite que a app defina as sugestões de tamanho da imagem de fundo do sistema."</string>
<string name="permlab_setTimeZone" msgid="7922618798611542432">"definir fuso horário"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Permite que a aplicação altere o fuso horário do tablet."</string>
- <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Permite que a aplicação altere o fuso horário do seu dispositivo Android TV."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Permite que a aplicação altere o fuso horário do telemóvel."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Permite que a app altere o fuso horário do tablet."</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Permite que a app altere o fuso horário do seu dispositivo Android TV."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Permite que a app altere o fuso horário do telemóvel."</string>
<string name="permlab_getAccounts" msgid="5304317160463582791">"procurar contas no dispositivo"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Permite que a aplicação obtenha a lista de contas reconhecidas pelo tablet. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
- <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permite que a aplicação obtenha a lista de contas reconhecidas pelo seu dispositivo Android TV. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
- <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permite que a aplicação obtenha a lista de contas reconhecidas pelo telemóvel. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Permite que a app obtenha a lista de contas reconhecidas pelo tablet. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permite que a app obtenha a lista de contas reconhecidas pelo seu dispositivo Android TV. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permite que a app obtenha a lista de contas reconhecidas pelo telemóvel. Pode incluir qualquer conta criada pelas aplicações instaladas."</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"ver ligações de rede"</string>
- <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Permite que a aplicação visualize informações acerca das ligações de rede como, por exemplo, que redes que existem e estão ligadas."</string>
+ <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Permite que a app visualize informações acerca das ligações de rede como, por exemplo, que redes que existem e estão ligadas."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"ter acesso total à rede"</string>
- <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Permite que a aplicação crie ligações de rede e utilize protocolos de rede personalizados. O navegador e outras aplicações fornecem meios para enviar dados para a Internet, pelo que esta autorização não é necessária para enviar dados para a Internet."</string>
+ <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Permite que a app crie ligações de rede e utilize protocolos de rede personalizados. O navegador e outras aplicações fornecem meios para enviar dados para a Internet, pelo que esta autorização não é necessária para enviar dados para a Internet."</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"mudar conectividade de rede"</string>
- <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Permite que a aplicação altere o estado de conectividade da rede."</string>
+ <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Permite que a app altere o estado de conectividade da rede."</string>
<string name="permlab_changeTetherState" msgid="9079611809931863861">"alterar conectividade associada"</string>
- <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Permite que a aplicação altere o estado de conectividade da rede ligada."</string>
+ <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Permite que a app altere o estado de conectividade da rede ligada."</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"ver ligações Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Permite que a aplicação visualize informações acerca de redes Wi-Fi como, por exemplo, se o Wi-Fi está ativado e o nome dos dispositivos Wi-Fi ligados."</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Permite que a app visualize informações acerca de redes Wi-Fi como, por exemplo, se o Wi-Fi está ativado e o nome dos dispositivos Wi-Fi ligados."</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"ligar e desligar de redes Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Permite que a aplicação se ligue e desligue de pontos de acesso Wi-Fi e que efetue alterações à configuração do dispositivo para redes Wi-Fi."</string>
+ <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Permite que a app se ligue e desligue de pontos de acesso Wi-Fi e que efetue alterações à configuração do dispositivo para redes Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"permitir recepção Multicast Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permite que a aplicação receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o tablet. Utiliza mais energia do que o modo não multicast."</string>
- <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Permite que a aplicação receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o seu dispositivo Android TV. Utiliza mais energia do que o modo não multicast."</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permite que a aplicação receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o telemóvel. Utiliza mais energia do que o modo não multicast."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permite que a app receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o tablet. Utiliza mais energia do que o modo não multicast."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Permite que a app receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o seu dispositivo Android TV. Utiliza mais energia do que o modo não multicast."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permite que a app receba pacotes enviados para todos os dispositivos numa rede Wi-Fi através de endereços multicast, não apenas para o telemóvel. Utiliza mais energia do que o modo não multicast."</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"aceder às definições de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permite à aplicação configurar o tablet Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permite que a aplicação configure o Bluetooth no seu dispositivo Android TV, bem como descubra e sincronize com dispositivos remotos."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permite que a aplicação configure o telemóvel Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permite à app configurar o tablet Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permite que a app configure o Bluetooth no seu dispositivo Android TV, bem como descubra e sincronize com dispositivos remotos."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permite que a app configure o telemóvel Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"ligar e desligar do WiMAX"</string>
- <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Permite que a aplicação determine se o WiMAX está ativado e aceda a informações acerca de qualquer rede WiMAX que esteja ligada."</string>
+ <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Permite que a app determine se o WiMAX está ativado e aceda a informações acerca de qualquer rede WiMAX que esteja ligada."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"alterar estado do WiMAX"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Permite que a aplicação ligue e desligue o tablet de redes WiMAX."</string>
- <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Permite que a aplicação ligue e desligue o seu dispositivo Android TV de redes WiMAX."</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permite que a aplicação ligue e desligue o telemóvel de redes WiMAX."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Permite que a app ligue e desligue o tablet de redes WiMAX."</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Permite que a app ligue e desligue o seu dispositivo Android TV de redes WiMAX."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permite que a app ligue e desligue o telemóvel de redes WiMAX."</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"sincronizar com dispositivos Bluetooth"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permite que a aplicação visualize a configuração do Bluetooth no tablet e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite que a aplicação visualize a configuração do Bluetooth no seu dispositivo Android TV e que estabeleça e aceite ligações com dispositivos sincronizados."</string>
- <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite que a aplicação visualize a configuração do Bluetooth no telemóvel e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permite que a app visualize a configuração do Bluetooth no tablet e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite que a app visualize a configuração do Bluetooth no seu dispositivo Android TV e que estabeleça e aceite ligações com dispositivos sincronizados."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite que a app visualize a configuração do Bluetooth no telemóvel e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informações de serviços de pagamento com NFC preferenciais"</string>
- <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que a aplicação obtenha informações de serviços de pagamento com NFC preferenciais, como apoios registados e destino da rota."</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que a app obtenha informações de serviços de pagamento com NFC preferenciais, como apoios registados e destino da rota."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlo Near Field Communication"</string>
- <string name="permdesc_nfc" msgid="8352737680695296741">"Permite que a aplicação comunique com etiquetas, cartões e leitores Near Field Communication (NFC)."</string>
+ <string name="permdesc_nfc" msgid="8352737680695296741">"Permite que a app comunique com etiquetas, cartões e leitores Near Field Communication (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"desativar o bloqueio do ecrã"</string>
- <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que a aplicação desative o bloqueio de teclas e qualquer segurança por palavra-passe associada. Por exemplo, o telemóvel desativa o bloqueio de teclas quando recebe uma chamada e reativa o bloqueio de teclas ao terminar a chamada."</string>
+ <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite que a app desative o bloqueio de teclas e qualquer segurança por palavra-passe associada. Por exemplo, o telemóvel desativa o bloqueio de teclas quando recebe uma chamada e reativa o bloqueio de teclas ao terminar a chamada."</string>
<string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"solicitar a complexidade do bloqueio de ecrã"</string>
- <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que a aplicação aprenda o nível de complexidade do bloqueio de ecrã (elevado, médio, baixo ou nenhum), que indica o intervalo de comprimento e o tipo de bloqueio de ecrã possíveis. A aplicação também pode sugerir aos utilizadores que atualizem o bloqueio de ecrã para um determinado nível, mas estes podem ignorar livremente a sugestão e continuar a navegação. Tenha em atenção que o bloqueio de ecrã não é armazenado em texto simples, pelo que a aplicação desconhece a palavra-passe exata."</string>
+ <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que a app aprenda o nível de complexidade do bloqueio de ecrã (elevado, médio, baixo ou nenhum), que indica o intervalo de comprimento e o tipo de bloqueio de ecrã possíveis. A app também pode sugerir aos utilizadores que atualizem o bloqueio de ecrã para um determinado nível, mas estes podem ignorar livremente a sugestão e continuar a navegação. Tenha em atenção que o bloqueio de ecrã não é armazenado em texto simples, pelo que a app desconhece a palavra-passe exata."</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"Utilizar hardware biométrico"</string>
- <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permite que a aplicação utilize hardware biométrico para autenticação."</string>
+ <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permite que a app utilize hardware biométrico para autenticação."</string>
<string name="permlab_manageFingerprint" msgid="7432667156322821178">"gerir o hardware de impressão digital"</string>
- <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que a aplicação invoque métodos para adicionar e eliminar modelos de impressão digital para utilização."</string>
+ <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que a app invoque métodos para adicionar e eliminar modelos de impressão digital para utilização."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"utilizar o hardware de impressão digital"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que a aplicação utilize o hardware de impressão digital para autenticação"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que a app utilize o hardware de impressão digital para autenticação"</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"modificar a sua coleção de música"</string>
- <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que a aplicação modifique a sua coleção de música."</string>
+ <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que a app modifique a sua coleção de música."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"modificar a sua coleção de vídeos"</string>
- <string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite que a aplicação modifique a sua coleção de vídeos."</string>
+ <string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite que a app modifique a sua coleção de vídeos."</string>
<string name="permlab_imagesWrite" msgid="1774555086984985578">"modificar a sua coleção de fotos"</string>
- <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a aplicação modifique a sua coleção de fotos."</string>
+ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a app modifique a sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ler as localizações a partir da sua coleção de multimédia"</string>
- <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a aplicação leia as localizações a partir da sua coleção de multimédia."</string>
+ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a app leia as localizações a partir da sua coleção de multimédia."</string>
<string name="biometric_dialog_default_title" msgid="5284880398508155088">"Confirme a sua identidade"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
@@ -568,9 +568,9 @@
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"gerir hardware de Desbloqueio facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite à aplicação invocar métodos para adicionar e eliminar modelos faciais para uso."</string>
+ <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite à app invocar métodos para adicionar e eliminar modelos faciais para uso."</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilizar hardware de Desbloqueio facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que a aplicação utilize hardware de Desbloqueio facial para autenticação"</string>
+ <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que a app utilize hardware de Desbloqueio facial para autenticação"</string>
<string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueio facial"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Volte a inscrever o seu rosto"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para melhorar o reconhecimento, volte a inscrever o seu rosto."</string>
@@ -612,63 +612,63 @@
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler definições de sincronização"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que a aplicação leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a aplicação Pessoas está sincronizada com uma conta."</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que a app leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a app Pessoas está sincronizada com uma conta."</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"ativar e desativar a sincronização"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Permite que uma aplicação modifique as definições de sincronização de uma conta. Por exemplo, pode ser utilizada para ativar a sincronização da aplicação Pessoas com uma conta."</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Permite que uma app modifique as definições de sincronização de uma conta. Por exemplo, pode ser utilizada para ativar a sincronização da app Pessoas com uma conta."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"ler estatísticas de sincronização"</string>
- <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Permite que uma aplicação leia o estado de sincronização de uma conta, incluindo o histórico de eventos de sincronização e a quantidade de dados sincronizados."</string>
+ <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Permite que uma app leia o estado de sincronização de uma conta, incluindo o histórico de eventos de sincronização e a quantidade de dados sincronizados."</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"ler os conteúdos do armazen. partilhado"</string>
- <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Permite que a aplicação leia conteúdos do armazenamento partilhado."</string>
+ <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Permite que a app leia conteúdos do armazenamento partilhado."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"modif./elim. os conteúdos do armazenam. partilhado"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Permite que a apl. escreva conteúd. do armazen. partilhado."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"efetuar/receber chamadas SIP"</string>
- <string name="permdesc_use_sip" msgid="3590270893253204451">"Permite que a aplicação efetue e receba chamadas SIP."</string>
+ <string name="permdesc_use_sip" msgid="3590270893253204451">"Permite que a app efetue e receba chamadas SIP."</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"registar novas ligações SIM de telecomunicações"</string>
- <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Permite que a aplicação registe novas ligações SIM de telecomunicações."</string>
+ <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Permite que a app registe novas ligações SIM de telecomunicações."</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"registar novas ligações de telecomunicações"</string>
- <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Permite que a aplicação registe novas ligações de telecomunicação."</string>
+ <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Permite que a app registe novas ligações de telecomunicação."</string>
<string name="permlab_connection_manager" msgid="3179365584691166915">"gerir ligações de telecomunicação"</string>
- <string name="permdesc_connection_manager" msgid="1426093604238937733">"Permite que a aplicação faça a gestão das ligações de telecomunicação."</string>
+ <string name="permdesc_connection_manager" msgid="1426093604238937733">"Permite que a app faça a gestão das ligações de telecomunicação."</string>
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"interagir com o ecrã durante uma chamada"</string>
- <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Permite que a aplicação controle quando e como o utilizador vê o ecrã durante uma chamada."</string>
+ <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Permite que a app controle quando e como o utilizador vê o ecrã durante uma chamada."</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"Interagir com serviços telefónicos"</string>
- <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Permite à aplicação interagir com serviços telefónicos e fazer/receber chamadas."</string>
+ <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Permite à app interagir com serviços telefónicos e fazer/receber chamadas."</string>
<string name="permlab_control_incall_experience" msgid="6436863486094352987">"proporcionar uma experiência de utilizador em chamada"</string>
- <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Permite que a aplicação proporcione uma experiência de utilizador em chamada."</string>
+ <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Permite que a app proporcione uma experiência de utilizador em chamada."</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"ler utilização histórica da rede"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Permite que a aplicação leia utilização histórica da rede para redes e aplicações específicas."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Permite que a app leia utilização histórica da rede para redes e aplicações específicas."</string>
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"gerir a política de rede"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Permite que a app faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"modificar contabilização da utilização da rede"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Permite que a app modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"aceder às notificações"</string>
- <string name="permdesc_accessNotifications" msgid="761730149268789668">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
+ <string name="permdesc_accessNotifications" msgid="761730149268789668">"Permite que a app obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"vincular a um serviço de escuta de notificações"</string>
<string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"vincular a um serviço de fornecedor de condição"</string>
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Permite que o titular vincule a interface de nível superior de um serviço de fornecedor de condição. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"vincular-se a um serviço de sonho"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Permite ao detentor ficar vinculado à interface de nível superior de um serviço de sonho. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invocar a aplicação de configuração fornecida pela operadora"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invocar a app de configuração fornecida pela operadora"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Permite que o titular invoque a app de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"ouvir observações sobre as condições da rede"</string>
- <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Permite que uma app ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"alterar a calibragem de entrada do dispositivo"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Permite à aplicação modificar os parâmetros de calibragem do ecrã tátil. Esta funcionalidade nunca deverá ser necessária para aplicações normais."</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Permite à app modificar os parâmetros de calibragem do ecrã tátil. Esta funcionalidade nunca deverá ser necessária para aplicações normais."</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"Aceder a certificados DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Permite que uma aplicação forneça e utilize certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Permite que uma app forneça e utilize certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"receber estado de transferência do Android Beam"</string>
- <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Permite que esta aplicação receba informações acerca das transferências atuais do Android Beam"</string>
+ <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Permite que esta app receba informações acerca das transferências atuais do Android Beam"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remover certificados DRM"</string>
- <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permite que uma aplicação remova certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permite que uma app remova certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"ligar ao serviço de mensagens de um operador"</string>
<string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permite ao titular ligar à interface de nível superior do serviço de mensagens de um operador. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular a serviços do operador"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite ao titular vincular-se a serviços do operador. Nunca deverá ser necessário nas aplicações normais."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"aceder a Não incomodar"</string>
- <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite à aplicação ler e alterar a configuração de Não incomodar"</string>
+ <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite à app ler e alterar a configuração de Não incomodar"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar utilização da autorização de visualização"</string>
- <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que o titular inicie a utilização de autorizações para uma aplicação. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que o titular inicie a utilização de autorizações para uma app. Nunca deverá ser necessário para aplicações normais."</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Definir regras de palavra-passe"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar o comprimento e os carateres permitidos nos PINs e nas palavras-passe do bloqueio de ecrã."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -695,7 +695,7 @@
<string name="policylab_expirePassword" msgid="6015404400532459169">"Def. exp. p.-passe bloq. ecrã"</string>
<string name="policydesc_expirePassword" msgid="9136524319325960675">"Alterar a frequência com que a palavra-passe, o PIN ou a sequência do bloqueio de ecrã deve ser alterado."</string>
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"Def. encriptação armazenamento"</string>
- <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Solicitar encriptação dos dados da aplicação armazenados."</string>
+ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Solicitar encriptação dos dados da app armazenados."</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"Desativar câmaras"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"Evitar a utilização de todas as câmaras do dispositivo."</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Desat. funcionalid. bloq. ecrã"</string>
@@ -951,17 +951,17 @@
<string name="autofill_area" msgid="8289022370678448983">"Área"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Emirado"</string>
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"ler os marcadores da Web e o histórico"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Permite que a aplicação leia o histórico de todos os URLs visitados pelo Navegador e todos os marcadores do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Permite que a app leia o histórico de todos os URLs visitados pelo Navegador e todos os marcadores do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
<string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"gravar marcadores da Web e o histórico"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Permite que a aplicação modifique o histórico do Navegador ou marcadores guardados no tablet. Isto pode permitir que a aplicação apague ou modifique dados do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Permite à aplicação modificar o histórico do navegador ou os marcadores armazenados no seu dispositivo Android TV. Isto pode permitir à aplicação apagar ou modificar dados do navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidade de navegação na Web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Permite que a aplicação modifique o histórico do Navegador ou marcadores guardados no telemóvel. Isto pode permitir que a aplicação apague ou modifique dados do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Permite que a app modifique o histórico do Navegador ou marcadores guardados no tablet. Isto pode permitir que a app apague ou modifique dados do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Permite à app modificar o histórico do navegador ou os marcadores armazenados no seu dispositivo Android TV. Isto pode permitir à app apagar ou modificar dados do navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidade de navegação na Web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Permite que a app modifique o histórico do Navegador ou marcadores guardados no telemóvel. Isto pode permitir que a app apague ou modifique dados do Navegador. Nota: esta autorização pode não ser aplicada por navegadores de terceiros ou outras aplicações com capacidades de navegação na Web."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"definir um alarme"</string>
- <string name="permdesc_setAlarm" msgid="2185033720060109640">"Permite que a aplicação defina um alarme numa aplicação de despertador instalada. Algumas aplicações de despertador podem não integrar esta funcionalidade."</string>
+ <string name="permdesc_setAlarm" msgid="2185033720060109640">"Permite que a app defina um alarme numa app de despertador instalada. Algumas aplicações de despertador podem não integrar esta funcionalidade."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"adicionar correio de voz"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permite que a aplicação adicione mensagens à sua caixa de entrada de correio de voz."</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permite que a app adicione mensagens à sua caixa de entrada de correio de voz."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"modificar permissões de geolocalização do Navegador"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Permite que a aplicação modifique as permissões de geolocalização do navegador. As aplicações maliciosas podem usar isto para permitir o envio de informações de localização para Web sites arbitrárias."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Permite que a app modifique as permissões de geolocalização do navegador. As aplicações maliciosas podem usar isto para permitir o envio de informações de localização para Web sites arbitrárias."</string>
<string name="save_password_message" msgid="2146409467245462965">"Quer que o browser memorize esta palavra-passe?"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"Agora não"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Lembrar"</string>
@@ -1111,7 +1111,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"Algumas funções do sistema poderão não funcionar"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Não existe armazenamento suficiente para o sistema. Certifique-se de que tem 250 MB de espaço livre e reinicie."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> em execução"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"Toque para obter mais informações ou para parar a aplicação."</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"Toque para obter mais informações ou para parar a app."</string>
<string name="ok" msgid="2646370155170753815">"OK"</string>
<string name="cancel" msgid="6908697720451760115">"Cancelar"</string>
<string name="yes" msgid="9069828999585032361">"OK"</string>
@@ -1130,8 +1130,8 @@
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Abrir"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com:"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"Abra os links com:"</string>
- <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Abra os links com a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Abra os links com a app <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Editar com %1$s"</string>
@@ -1142,28 +1142,28 @@
<string name="whichSendToApplication" msgid="77101541959464018">"Enviar com"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Enviar com %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Enviar"</string>
- <string name="whichHomeApplication" msgid="8276350727038396616">"Selecione uma aplicação Página inicial"</string>
+ <string name="whichHomeApplication" msgid="8276350727038396616">"Selecione uma app Página inicial"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Utilizar %1$s como Página inicial"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"Capturar imagem"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Capturar imagem com"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Capturar imagem com o %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagem"</string>
<string name="alwaysUse" msgid="3153558199076112903">"Utilizar por predefinição para esta ação."</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"Utilizar outra aplicação"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"Utilizar outra app"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"Limpar a predefinição nas Definições do Sistema > Aplicações > Transferidas."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Escolha uma ação"</string>
- <string name="chooseUsbActivity" msgid="2096269989990986612">"Escolher uma aplicação para o dispositivo USB"</string>
- <string name="noApplications" msgid="1186909265235544019">"Nenhuma aplicação pode efetuar esta ação."</string>
+ <string name="chooseUsbActivity" msgid="2096269989990986612">"Escolher uma app para o dispositivo USB"</string>
+ <string name="noApplications" msgid="1186909265235544019">"Nenhuma app pode efetuar esta ação."</string>
<string name="aerr_application" msgid="4090916809370389109">"<xliff:g id="APPLICATION">%1$s</xliff:g> sofreu uma falha de sistema."</string>
<string name="aerr_process" msgid="4268018696970966407">"<xliff:g id="PROCESS">%1$s</xliff:g> sofreu uma falha de sistema."</string>
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> continua a falhar"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> continua a falhar"</string>
- <string name="aerr_restart" msgid="2789618625210505419">"Abrir aplicação novamente"</string>
+ <string name="aerr_restart" msgid="2789618625210505419">"Abrir app novamente"</string>
<string name="aerr_report" msgid="3095644466849299308">"Enviar comentários"</string>
<string name="aerr_close" msgid="3398336821267021852">"Fechar"</string>
<string name="aerr_mute" msgid="2304972923480211376">"Desativar som até o dispositivo reiniciar"</string>
<string name="aerr_wait" msgid="3198677780474548217">"Aguardar"</string>
- <string name="aerr_close_app" msgid="8318883106083050970">"Fechar aplicação"</string>
+ <string name="aerr_close_app" msgid="8318883106083050970">"Fechar app"</string>
<string name="anr_title" msgid="7290329487067300120"></string>
<string name="anr_activity_application" msgid="8121716632960340680">"<xliff:g id="APPLICATION">%2$s</xliff:g> não está a responder"</string>
<string name="anr_activity_process" msgid="3477362583767128667">"<xliff:g id="ACTIVITY">%1$s</xliff:g> não está a responder"</string>
@@ -1181,10 +1181,10 @@
<string name="screen_compat_mode_hint" msgid="4032272159093750908">"Reative este modo nas Definições do Sistema > Aplicações > Transferidas."</string>
<string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> não suporta a definição de Tamanho do ecrã atual e pode ter um comportamento inesperado."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"Mostrar sempre"</string>
- <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da aplicação."</string>
+ <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da app."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostrar sempre"</string>
<string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Verificar atualizações"</string>
- <string name="smv_application" msgid="3775183542777792638">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
+ <string name="smv_application" msgid="3775183542777792638">"A app <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string>
<string name="smv_process" msgid="1398801497130695446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string>
<string name="android_upgrading_title" product="default" msgid="7279077384220829683">"O telemóvel está a atualizar…"</string>
<string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"O tablet está a atualizar…"</string>
@@ -1196,7 +1196,7 @@
<string name="android_upgrading_fstrim" msgid="3259087575528515329">"A otimizar o armazenamento."</string>
<string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"A concluir a atualização do sistema…"</string>
<string name="app_upgrading_toast" msgid="1016267296049455585">"O <xliff:g id="APPLICATION">%1$s</xliff:g> está a ser atualizado…"</string>
- <string name="android_upgrading_apk" msgid="1339564803894466737">"A otimizar a aplicação <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="android_upgrading_apk" msgid="1339564803894466737">"A otimizar a app <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_preparing_apk" msgid="589736917792300956">"A preparar o <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"A iniciar aplicações"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"A concluir o arranque."</string>
@@ -1204,14 +1204,14 @@
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toque para regressar ao jogo."</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Selecionar jogo"</string>
<string name="heavy_weight_switcher_text" msgid="6814316627367160126">"Para um melhor desempenho, só pode abrir um destes jogos de cada vez."</string>
- <string name="old_app_action" msgid="725331621042848590">"Regressar à aplicação <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_action" msgid="547772182913269801">"Abrir a aplicação <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1958903080400806644">"A aplicação <xliff:g id="OLD_APP">%1$s</xliff:g> vai fechar sem guardar."</string>
+ <string name="old_app_action" msgid="725331621042848590">"Regressar à app <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_action" msgid="547772182913269801">"Abrir a app <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_description" msgid="1958903080400806644">"A app <xliff:g id="OLD_APP">%1$s</xliff:g> vai fechar sem guardar."</string>
<string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> excedeu o limite da memória"</string>
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"A captura da área dinâmica para dados do processo <xliff:g id="PROC">%1$s</xliff:g> está pronta."</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"Foi recolhida a captura da área dinâmica para dados. Toque para partilhar."</string>
<string name="dump_heap_title" msgid="4367128917229233901">"Pretende partilhar a captura da área dinâmica para dados?"</string>
- <string name="dump_heap_text" msgid="1692649033835719336">"O processo <xliff:g id="PROC">%1$s</xliff:g> excedeu o respetivo limite de memória de <xliff:g id="SIZE">%2$s</xliff:g>. Está disponível uma captura da área dinâmica para dados para partilhar com o respetivo programador. Atenção: esta captura da área dinâmica para dados pode conter algumas das suas informações pessoais a que a aplicação tem acesso."</string>
+ <string name="dump_heap_text" msgid="1692649033835719336">"O processo <xliff:g id="PROC">%1$s</xliff:g> excedeu o respetivo limite de memória de <xliff:g id="SIZE">%2$s</xliff:g>. Está disponível uma captura da área dinâmica para dados para partilhar com o respetivo programador. Atenção: esta captura da área dinâmica para dados pode conter algumas das suas informações pessoais a que a app tem acesso."</string>
<string name="dump_heap_system_text" msgid="6805155514925350849">"O processo <xliff:g id="PROC">%1$s</xliff:g> excedeu o respetivo limite de memória de <xliff:g id="SIZE">%2$s</xliff:g>. Está disponível uma captura da área dinâmica para dados para partilhar. Atenção: esta captura da área dinâmica para dados pode conter informações pessoais confidenciais a que o processo tem acesso, que podem incluir coisas que escreveu."</string>
<string name="dump_heap_ready_text" msgid="5849618132123045516">"Está disponível uma captura da área dinâmica para dados do processo <xliff:g id="PROC">%1$s</xliff:g> para partilhar. Atenção: esta captura da área dinâmica para dados pode conter informações pessoais confidenciais a que o processo tem acesso, que podem incluir coisas que escreveu."</string>
<string name="sendText" msgid="493003724401350724">"Escolha uma ação para o texto"</string>
@@ -1262,7 +1262,7 @@
<string name="decline" msgid="6490507610282145874">"Recusar"</string>
<string name="select_character" msgid="3352797107930786979">"Introduzir carácter"</string>
<string name="sms_control_title" msgid="4748684259903148341">"A enviar mensagens SMS"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está a enviar um grande número de mensagens SMS. Pretende autorizar que a aplicação continue a enviar mensagens?"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está a enviar um grande número de mensagens SMS. Pretende autorizar que a app continue a enviar mensagens?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"Permitir"</string>
<string name="sms_control_no" msgid="4845717880040355570">"Recusar"</string>
<string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> gostaria de enviar uma mensagem para <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
@@ -1281,9 +1281,9 @@
<string name="sim_added_message" msgid="6602906609509958680">"Reinicie o aparelho para aceder à rede de telemóvel."</string>
<string name="sim_restart_button" msgid="8481803851341190038">"Reiniciar"</string>
<string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar o serviço móvel"</string>
- <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Transfira a aplicação do operador para ativar o seu novo SIM."</string>
- <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Transfira a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar o novo SIM."</string>
- <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Transferir aplicação"</string>
+ <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Transfira a app do operador para ativar o seu novo SIM."</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Transfira a app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar o novo SIM."</string>
+ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Transferir app"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo SIM inserido"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"Definir hora"</string>
@@ -1334,9 +1334,9 @@
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Sobrepor a outras aplicações"</string>
- <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"A aplicação <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras aplicações"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"A app <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras aplicações"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"O <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras app"</string>
- <string name="alert_windows_notification_message" msgid="6538171456970725333">"Se não pretende que a aplicação <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
+ <string name="alert_windows_notification_message" msgid="6538171456970725333">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
<string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desligar"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"A verificar o <xliff:g id="NAME">%s</xliff:g>…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"A rever o conteúdo atual…"</string>
@@ -1383,15 +1383,15 @@
<string name="ext_media_status_missing" msgid="6520746443048867314">"Não inserido"</string>
<string name="activity_list_empty" msgid="4219430010716034252">"Não foi encontrada nenhuma atividade correspondente."</string>
<string name="permlab_route_media_output" msgid="8048124531439513118">"encaminhar saída de som multimédia"</string>
- <string name="permdesc_route_media_output" msgid="1759683269387729675">"Permite que a aplicação encaminhe a saída de som multimédia para outros dispositivos externos."</string>
+ <string name="permdesc_route_media_output" msgid="1759683269387729675">"Permite que a app encaminhe a saída de som multimédia para outros dispositivos externos."</string>
<string name="permlab_readInstallSessions" msgid="7279049337895583621">"ler sessões de instalação"</string>
- <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Permite que uma aplicação leia sessões de instalação. Isto permite que veja detalhes acerca de instalações de pacotes ativas."</string>
+ <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Permite que uma app leia sessões de instalação. Isto permite que veja detalhes acerca de instalações de pacotes ativas."</string>
<string name="permlab_requestInstallPackages" msgid="7600020863445351154">"solicitar pacotes de instalação"</string>
- <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Permite que uma aplicação solicite a instalação de pacotes."</string>
+ <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Permite que uma app solicite a instalação de pacotes."</string>
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"solicitar eliminação de pacotes"</string>
- <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Permite que uma aplicação solicite a eliminação de pacotes."</string>
+ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Permite que uma app solicite a eliminação de pacotes."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"pedir para ignorar as otimizações da bateria"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que uma aplicação solicite autorização para ignorar as otimizações da bateria para a mesma."</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Permite que uma app solicite autorização para ignorar as otimizações da bateria para a mesma."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tocar duas vezes para controlar o zoom"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Não foi possível adicionar widget."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ir"</string>
@@ -1410,8 +1410,8 @@
<string name="deny" msgid="6632259981847676572">"Recusar"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"Permissão solicitada"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Permissão solicitada\npara a conta <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"Está a utilizar esta aplicação fora do seu perfil de trabalho"</string>
- <string name="forward_intent_to_work" msgid="3620262405636021151">"Está a utilizar esta aplicação no seu perfil de trabalho"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"Está a utilizar esta app fora do seu perfil de trabalho"</string>
+ <string name="forward_intent_to_work" msgid="3620262405636021151">"Está a utilizar esta app no seu perfil de trabalho"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Método de entrada"</string>
<string name="sync_binding_label" msgid="469249309424662147">"Sincronização"</string>
<string name="accessibility_binding_label" msgid="1974602776545801715">"Acessibilidade"</string>
@@ -1434,8 +1434,8 @@
<string name="no_file_chosen" msgid="4146295695162318057">"Não foi selecionado nenhum ficheiro"</string>
<string name="reset" msgid="3865826612628171429">"Repor"</string>
<string name="submit" msgid="862795280643405865">"Enviar"</string>
- <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"A aplicação de condução está em execução."</string>
- <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair da aplicação de condução."</string>
+ <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"A app de condução está em execução."</string>
+ <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair da app de condução."</string>
<string name="back_button_label" msgid="4078224038025043387">"Anterior"</string>
<string name="next_button_label" msgid="6040209156399907780">"Seguinte"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
@@ -1493,7 +1493,7 @@
<string name="keyboardview_keycode_mode_change" msgid="2743735349997999020">"Alteração do modo"</string>
<string name="keyboardview_keycode_shift" msgid="3026509237043975573">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="168054869339091055">"Enter"</string>
- <string name="activitychooserview_choose_application" msgid="3500574466367891463">"Escolher uma aplicação"</string>
+ <string name="activitychooserview_choose_application" msgid="3500574466367891463">"Escolher uma app"</string>
<string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Não foi possível iniciar <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="shareactionprovider_share_with" msgid="2753089758467748982">"Partilhar com:"</string>
<string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Compartilhar com <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
@@ -1523,7 +1523,7 @@
<string name="data_usage_restricted_body" msgid="5338694433686077733">"Toque para remover a restrição."</string>
<string name="data_usage_rapid_title" msgid="2950192123248740375">"Utilização elevada de dados móveis"</string>
<string name="data_usage_rapid_body" msgid="3886676853263693432">"As suas aplicações utilizaram mais dados do que o habitual."</string>
- <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"A aplicação <xliff:g id="APP">%s</xliff:g> utilizou mais dados do que o habitual."</string>
+ <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"A app <xliff:g id="APP">%s</xliff:g> utilizou mais dados do que o habitual."</string>
<string name="ssl_certificate" msgid="5690020361307261997">"Certificado de segurança"</string>
<string name="ssl_certificate_is_valid" msgid="7293675884598527081">"Este certificado é válido."</string>
<string name="issued_to" msgid="5975877665505297662">"Emitido para:"</string>
@@ -1639,7 +1639,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver e controlar o ecrã"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Pode ler todo o conteúdo do ecrã e sobrepor conteúdo a outras aplicações."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Veja e execute ações"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Pode monitorizar as suas interações com uma aplicação ou um sensor de hardware e interagir com aplicações em seu nome."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Pode monitorizar as suas interações com uma app ou um sensor de hardware e interagir com aplicações em seu nome."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Permitir"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Recusar"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toque numa funcionalidade para começar a utilizá-la:"</string>
@@ -1794,11 +1794,9 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
- <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada aplicação que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n•Ativa o tema escuro.\n•Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saber mais"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n•Ativa o tema escuro.\n•Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Pretende ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -1877,8 +1875,8 @@
<string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"É importante devido às pessoas envolvidas."</string>
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string>
- <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
- <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
+ <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
@@ -1886,8 +1884,8 @@
<string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"Todas as regiões"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"Pesquisa"</string>
- <string name="app_suspended_title" msgid="888873445010322650">"A aplicação não está disponível"</string>
- <string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicação <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível neste momento. A aplicação <xliff:g id="APP_NAME_1">%2$s</xliff:g> gere esta definição."</string>
+ <string name="app_suspended_title" msgid="888873445010322650">"A app não está disponível"</string>
+ <string name="app_suspended_default_message" msgid="6451215678552004172">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível neste momento. A app <xliff:g id="APP_NAME_1">%2$s</xliff:g> gere esta definição."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
@@ -1895,10 +1893,10 @@
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
- <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicação foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string>
+ <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar atualizações"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string>
- <string name="new_sms_notification_content" msgid="3197949934153460639">"Abra a aplicação de SMS para ver"</string>
+ <string name="new_sms_notification_content" msgid="3197949934153460639">"Abra a app de SMS para ver"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Algumas funcionalidades limitadas"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"Perfil de trabalho bloqueado"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Toque p/ desb. perfil trabalho"</string>
@@ -1908,7 +1906,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Fixar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Soltar"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Soltar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Info. da aplicação"</string>
+ <string name="app_info" msgid="6113278084877079851">"Info. da app"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"A iniciar a demonstração…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"A repor o dispositivo…"</string>
@@ -1978,15 +1976,15 @@
<string name="mmcc_illegal_me_msim_template" msgid="4802735138861422802">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> não autorizado"</string>
<string name="popup_window_default_title" msgid="6907717596694826919">"Janela pop-up"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"A aplicação foi alterada para a versão anterior ou não é compatível com este atalho."</string>
- <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Não foi possível restaurar o atalho porque a aplicação não é compatível com a funcionalidade de cópia de segurança e restauro."</string>
+ <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"A app foi alterada para a versão anterior ou não é compatível com este atalho."</string>
+ <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Não foi possível restaurar o atalho porque a app não é compatível com a funcionalidade de cópia de segurança e restauro."</string>
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Não foi possível restaurar o atalho devido a uma falha de correspondência entre as assinaturas das aplicações."</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Não foi possível restaurar o atalho."</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"O atalho está desativado."</string>
<string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALAR"</string>
<string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ABRIR MESMO ASSIM"</string>
<string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplicação prejudicial detetada"</string>
- <string name="slices_permission_request" msgid="3677129866636153406">"A aplicação <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>."</string>
+ <string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"As chamadas e as notificações vibram."</string>
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"É desativado o som das chamadas e das notificações."</string>
@@ -2010,7 +2008,7 @@
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"O tablet tem carga suficiente. As funcionalidades já não estão restritas."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"O dispositivo tem carga suficiente. As funcionalidades já não estão restritas."</string>
<string name="mime_type_folder" msgid="2203536499348787650">"Pasta"</string>
- <string name="mime_type_apk" msgid="3168784749499623902">"Aplicação para Android"</string>
+ <string name="mime_type_apk" msgid="3168784749499623902">"App para Android"</string>
<string name="mime_type_generic" msgid="4606589110116560228">"Ficheiro"</string>
<string name="mime_type_generic_ext" msgid="9220220924380909486">"Ficheiro <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="mime_type_audio" msgid="4933450584432509875">"Áudio"</string>
@@ -2035,7 +2033,7 @@
</plurals>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não existem pessoas recomendadas com quem partilhar"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicações"</string>
- <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Página inicial"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Anterior"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplicações recentes"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de energia"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecrã de bloqueio"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de ecrã"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
<skip />
- <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
+ <skip />
+ <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"> <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8c37b5e..dbd69a1 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Caixa de diálogo de liga/desliga"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+ <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0f95ecc..02e3fda 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n•·activează tema întunecată;\n•·dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n• activează tema întunecată;\n• dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activați Economizorul de date?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activați"</string>
@@ -2078,15 +2076,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Power Dialog"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a trimis o imagine"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversație"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversație de grup"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c2e35eb..b804754 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string>
<string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Диалоговое окно питания"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"Отправлено изображение"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групповой чат"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 03ef434..103bc39 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1796,10 +1796,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්රියාත්මක කරයි\n•පසුබිමේ ක්රියාකාරකම, සමහර දෘෂ්ය ප්රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්රියාත්මක කරයි\n•පසුබිමේ ක්රියාකාරකම, සමහර දෘෂ්ය ප්රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string>
<string name="data_saver_description" msgid="4995164271550590517">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"දත්ත සුරැකුම ක්රියාත්මක කරන්නද?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ක්රියාත්මක කරන්න"</string>
@@ -2046,15 +2044,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"බල සංවාදය"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"රූපයක් එව්වා"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"සංවාදය"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"සමූහ සංවාදය"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index bee9e726..485ee11 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -204,12 +204,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Zapnite svoj pracovný profil"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vaše osobné aplikácie sú zablokované, dokým nezapnete svoj pracovný profil"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Vaše osobné aplikácie budú zajtra zablokované"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Zapnúť pracovný profil"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string>
@@ -1843,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n•vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového slova „Hey Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n• vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového slova „Hey Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string>
@@ -2115,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialógové okno napájania"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"odoslal(a) obrázok"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzácia"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzácia"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b22cb17..b8bb8af 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -204,12 +204,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Vklopite delovni profil"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Osebne aplikacije so blokirane, dokler ne vklopite delovnega profila"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Osebne aplikacije bodo blokirane jutri"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Vklopi delovni profil"</string>
<string name="me" msgid="6207584824693813140">"Jaz"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabličnega računalnika"</string>
@@ -1843,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n•Vklopi temno temo,\n•izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n•Vklopi temno temo,\n•izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Vklop"</string>
@@ -2115,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Pogovorno okno o porabi energije"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslal(-a) sliko"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pogovor"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinski pogovor"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 10cb62d..55f006e 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n•Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”\n\n"<annotation id="url">"Mëso më shumë"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n•Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivizo"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogu i energjisë"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"dërgoi një imazh"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Biseda"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Bisedë në grup"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 67e1ff4..d149e27 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -184,11 +184,11 @@
<item quantity="other">Инсталирани су ауторитети за издавање сертификата</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Од стране непознате треће стране"</string>
- <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Од стране администратора профила за Work"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Од стране администратора пословног профила"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Од стране <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="work_profile_deleted" msgid="5891181538182009328">"Пословни профил је избрисан"</string>
- <string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликација за администраторе на профилу за Work недостаје или је оштећена. Због тога су профил за Work и повезани подаци избрисани. Обратите се администратору за помоћ."</string>
- <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Профил за Work више није доступан на овом уређају"</string>
+ <string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликација за администраторе на пословном профилу недостаје или је оштећена. Због тога су пословни профил и повезани подаци избрисани. Обратите се администратору за помоћ."</string>
+ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Пословни профил више није доступан на овом уређају"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Превише покушаја уноса лозинке"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"Администратор је уступио уређај за личну употребу"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"Уређајем се управља"</string>
@@ -202,10 +202,10 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Укључите профил за Work"</string>
- <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личне апликације су блокиране док не укључите профил за Work"</string>
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Укључите пословни профил"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личне апликације су блокиране док не укључите пословни профил"</string>
<string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Личне апликације ће бити блокиране сутра"</string>
- <string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Укључи профил за Work"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Укључи пословни профил"</string>
<string name="me" msgid="6207584824693813140">"Ја"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опције за таблет"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опције Android TV-а"</string>
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Да би се продужило трајање батерије, Уштеда батерије:\n\n•укључује тамну тему\n•искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Да би се продужило трајање батерије, Уштеда батерије:\n\n•укључује тамну тему\n•искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Укључи"</string>
@@ -1887,7 +1885,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS захтев је промењен у видео позив"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS захтев је промењен у USSD захтев"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Промењено је у нови SS захтев"</string>
- <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Профил за Work"</string>
+ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Пословни профил"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Обавештено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Прошири"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Скупи"</string>
@@ -1922,8 +1920,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Апликација <xliff:g id="APP_NAME_0">%1$s</xliff:g> тренутно није доступна. <xliff:g id="APP_NAME_1">%2$s</xliff:g> управља доступношћу."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Сазнајте више"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Опозови паузирање апликације"</string>
- <string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо профил за Work?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције профила за Work"</string>
+ <string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо пословни профил?"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције пословног профила"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
@@ -1932,8 +1930,8 @@
<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>
- <string name="profile_encrypted_detail" msgid="5279730442756849055">"Профил за Work је закључан"</string>
- <string name="profile_encrypted_message" msgid="1128512616293157802">"Додиром откљ. профил за Work"</string>
+ <string name="profile_encrypted_detail" msgid="5279730442756849055">"Пословни профил је закључан"</string>
+ <string name="profile_encrypted_message" msgid="1128512616293157802">"Додиром откљ. пословни профил"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Повезано је са производом <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Додирните за преглед датотека"</string>
<string name="pin_target" msgid="8036028973110156895">"Закачи"</string>
@@ -2078,15 +2076,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Дијалог напајања"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"је послао/ла слику"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Конверзација"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групна конверзација"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
@@ -2095,14 +2094,14 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Лични приказ"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Приказ за посао"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Не можете да делите овај садржај помоћу апликација за посао"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"ИТ администратор вам не дозвољава да делите овај садржај помоћу апликација на профилу за Work"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"ИТ администратор вам не дозвољава да делите овај садржај помоћу апликација на пословном профилу"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Не можете да отворите овај садржај помоћу апликација за посао"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"ИТ администратор вам не дозвољава да отворите овај садржај помоћу апликација на профилу за Work"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"ИТ администратор вам не дозвољава да отворите овај садржај помоћу апликација на пословном профилу"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Не можете да делите овај садржај помоћу личних апликација"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"ИТ администратор вам не дозвољава да делите овај садржај помоћу апликација на личном профилу"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Не можете да отворите овај садржај помоћу личних апликација"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"ИТ администратор вам не дозвољава да отворите овај садржај помоћу апликација на личном профилу"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Профил за Work је паузиран"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Пословни профил је паузиран"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Укључи"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Ниједна апликација за посао не може да подржава овај садржај"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Ниједна апликација за посао не може да отвори овај садржај"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 840493c..bb268cce 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n•·inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”\n\n"<annotation id="url">"Läs mer"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n•·inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivera"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialogruta för ström"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmdump"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har skickat en bild"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konversation"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppkonversation"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 360f41b..4f9376c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Washa wasifu wako wa kazini"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Programu zako za binafsi zimezuiwa hadi uwashe wasifu wako wa kazini"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"Programu zako za binafsi zitazuiwa kesho"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"Washa wasifu wa kazini"</string>
<string name="me" msgid="6207584824693813140">"Mimi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Chaguo za kompyuta ndogo"</string>
@@ -1797,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n•Huwasha Mandhari meusi\n•Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n•Huwasha Mandhari meusi\n•Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ungependa Kuwasha Kiokoa Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Washa"</string>
@@ -1894,7 +1889,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Pata maelezo zaidi"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Acha kusimamisha programu"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ungependa kuwasha wasifu wa kazini?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini, arifa na vipengele vingine vya wasifu wa kazini"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini na vipengele vingine vya wasifu wa kazini"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
@@ -2047,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kidirisha cha Nishati"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"alituma picha"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Mazungumzo"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Mazungumzo ya Kikundi"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index c2c9d16..97b2afd 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -200,12 +200,9 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string>
- <!-- no translation found for personal_apps_suspension_title (7561416677884286600) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_text (6115455688932935597) -->
- <skip />
- <!-- no translation found for personal_apps_suspension_tomorrow_text (6322541302153673994) -->
- <skip />
+ <string name="personal_apps_suspension_title" msgid="7561416677884286600">"பணிக் கணக்கை ஆன் செய்யுங்கள்"</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"பணிக் கணக்கை ஆன் செய்யும் வரை உங்கள் தனிப்பட்ட ஆப்ஸ் தடுக்கப்பட்டிருக்கும்"</string>
+ <string name="personal_apps_suspension_tomorrow_text" msgid="6322541302153673994">"நாளை உங்கள் தனிப்பட்ட ஆப்ஸ் தடுக்கப்படும்"</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="4278188538997940785">"பணிக் கணக்கை ஆன் செய்"</string>
<string name="me" msgid="6207584824693813140">"நான்"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"டேப்லெட் விருப்பங்கள்"</string>
@@ -2047,9 +2044,11 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"பவர் உரையாடல்"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index b9ef76a..1b1d43f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి, బ్యాటరీ సేవర్ వీటిని చేస్తుంది:\n\n•ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది\n•బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లతో పాటు “Ok Google” వంటి ఇతర ఫీచర్లను ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది\n\n"<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి, బ్యాటరీ సేవర్ వీటిని చేస్తుంది:\n\n•ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది\n•బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లతో పాటు “Ok Google” వంటి ఇతర ఫీచర్లను ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది"</string>
<string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్గ్రౌండ్లో కొన్ని యాప్లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్, డేటాను యాక్సెస్ చేయగలదు. కానీ తక్కువ సార్లు మాత్రమే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్ను ఆన్ చేయాలా?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ఆన్ చేయి"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"పవర్ డైలాగ్ను తెరువు"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ఇమేజ్ను పంపారు"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"సంభాషణ"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"గ్రూప్ సంభాషణ"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 6b8b912..80c7a59 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n•เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n•เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"กล่องโต้ตอบพลังงาน"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ส่งรูปภาพ"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"การสนทนา"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"บทสนทนากลุ่ม"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f078b82..e1e9ca8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n•I-on ang Madilim na tema\n•I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n•I-on ang Madilim na tema\n•I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog ng Power"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nagpadala ng larawan"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pag-uusap"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Panggrupong Pag-uusap"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a0ff1a8..05984a0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n•Koyu temayı açar\n•Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n•Koyu temayı açar\n•Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Veri Tasarrufu açılsın mı?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aç"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Güç İletişim Kutusu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"bir resim gönderildi"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Görüşme"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grup Görüşmesi"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index da529bc..fe373a1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1840,10 +1840,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n•вмикає темну тему;\n•припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\".\n\n"<annotation id="url">"Докладніше"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n•вмикає темну тему;\n•припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Увімкнути заощадження трафіку?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Увімкнути"</string>
@@ -2112,15 +2110,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Відкрити вікно"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"надіслано зображення"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Груповий чат"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 0f09c61..f2ed250 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n\n•گہری تھیم کو آن کرتی ہے\n•پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n\n•گہری تھیم کو آن کرتی ہے\n•پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتی ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا تک رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا اکثر نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ڈیٹا سیور آن کریں؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"آن کریں"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"پاور ڈائیلاگ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ایک تصویر بھیجی"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"گفتگو"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"گروپ گفتگو"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"+<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d069a68..e072557 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -472,7 +472,7 @@
<string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Dasturga planshetdagi infraqizil antenadan foydalanish ruxsatini beradi."</string>
<string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Ilovaga Android TV qurilmangizning infraqizil uzatkichidan foydalanish huquqini beradi."</string>
<string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Dasturga telefondagi infraqizil antenadan foydalanish ruxsatini beradi."</string>
- <string name="permlab_setWallpaper" msgid="6959514622698794511">"fonga rasm o‘rnatish"</string>
+ <string name="permlab_setWallpaper" msgid="6959514622698794511">"fonga rasm tanlash"</string>
<string name="permdesc_setWallpaper" msgid="2973996714129021397">"Ilova tizim uchun orqa fon rasmlarini o‘rnatishi mumkin."</string>
<string name="permlab_setWallpaperHints" msgid="1153485176642032714">"fon rasmi o‘lchamini moslash"</string>
<string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Ilova tizimning orqa fon rasmlari uchun o‘lchamlarini ko‘rsatishi mumkin."</string>
@@ -1221,7 +1221,7 @@
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Ovozsiz rejim tanlandi"</string>
<string name="volume_call" msgid="7625321655265747433">"Suhbat vaqtidagi tovush balandligi"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Kiruvchi bluetooth tovushi"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"Signal tovushi"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"Signal balandligi"</string>
<string name="volume_notification" msgid="6864412249031660057">"Eslatma tovushi"</string>
<string name="volume_unknown" msgid="4041914008166576293">"Tovush balandligi"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetooth tovushi"</string>
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n•Tungi mavzuni yoqadi\n•Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n•Tungi mavzuni yoqadi\n•Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Yoqish"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Quvvat muloqot oynasi"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"rasm yuborildi"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Suhbat"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Guruh suhbati"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 479574b..8579414 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n•Bật Giao diện tối\n•Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n•Bật Giao diện tối\n•Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bật"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Hộp thoại thao tác với nguồn"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"đã gửi hình ảnh"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Cuộc trò chuyện"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Cuộc trò chuyện nhóm"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7f54194..7b3ca76 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”\n\n"<annotation id="url">"了解详情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要开启流量节省程序吗?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"开启"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"电源对话框"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"发送了一张图片"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"对话"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群组对话"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
@@ -2068,7 +2067,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"您的 IT 管理员不允许您通过个人资料中的应用分享此内容"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"无法通过个人应用打开此内容"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"您的 IT 管理员不允许您通过个人资料中的应用打开此内容"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"工作资料已暂停使用"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"工作资料已被暂停"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"开启"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"任何工作应用都不支持此内容"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"任何工作应用都无法打开此内容"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d71d2c5..30a596a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為延長電池壽命,「省電模式」會:\n\n•開啟深色主題背景\n•關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"為延長電池壽命,「省電模式」會:\n\n•開啟深色主題背景\n•關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟「數據節省模式」嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源對話框"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"已傳送圖片"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 3c0312b..ac5ebaa 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"開啟電源對話方塊"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"傳送了一張圖片"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4acf3fe..32a31f7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5997766757551917769) -->
- <skip />
- <!-- no translation found for battery_saver_description (8587408568232177204) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Ukuze unwebe impilo yebhethri, Isilondolozi Sebhethri:\n\n•Sivula itimu emnyama\n•Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"Ukuze unwebe impilo yebhethri, Isilondolozi sebhethri:\n\n•Sivula itimu emnyama\n•Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vula iseva yedatha?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Vula"</string>
@@ -2044,15 +2042,16 @@
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Ibhokisi lamandla"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string>
- <!-- no translation found for accessibility_system_action_accessibility_button_label (5941347017132886642) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_label (8488701469459210309) -->
<skip />
- <!-- no translation found for accessibility_system_action_accessibility_button_chooser_label (6973618519666227981) -->
+ <!-- no translation found for accessibility_system_action_on_screen_a11y_shortcut_chooser_label (1057878690209817886) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_hardware_a11y_shortcut_label (5764644187715255107) -->
<skip />
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
- <!-- no translation found for conversation_single_line_image_placeholder (6983271082911936900) -->
- <skip />
+ <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"uthumele isithombe"</string>
<string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Ingxoxo"</string>
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ingxoxo Yeqembu"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a8d1605..b92bbd6 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4820,7 +4820,7 @@
May be a string value, which is a comma-separated language tag list, such as "ja-JP,zh-CN".
When not specified or an empty string is given, it will fallback to the default one.
{@see android.os.LocaleList#forLanguageTags(String)}
- {@see android.text.TextView#setTextLocales(android.os.LocaleList)} -->
+ {@see android.widget.TextView#setTextLocales(android.os.LocaleList)} -->
<attr name="textLocale" format="string" />
<!-- Text color for links. -->
<attr name="textColorLink" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2a2da6a..c962256 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1830,9 +1830,30 @@
<!-- @hide no longer used, kept to preserve padding -->
<attr name="allowAutoRevokePermissionsExemption" format="boolean" />
+ <!-- Declare the app's tolerance to having its permissions automatically revoked when unused for an extended
+ period of time -->
<attr name="autoRevokePermissions">
+ <!-- App supports re-requesting its permissions if revoked.
+ Revoking app's permissions doesn't cause user experience issues, aside from a repeated permission request.
+
+ Permissions may be automatically revoked from an app if unused. The app must check and possibly request the
+ necessary permission on each permission-gated call-->
<enum name="allowed" value="0" />
+ <!-- App may experience degraded functionality when its previously-granted permissions are revoked.
+ Revoking app's permissions may cause user experience issues, that are not critical to the user.
+
+ Apps with this declaration can choose to request an exemption from auto revoke from user by starting
+ an activity with {@code Intent.ACTION_AUTO_REVOKE_PERMISSIONS}. -->
<enum name="discouraged" value="1" />
+ <!-- User may experience severe consequences if this app's permissions are revoked unexpectedly.
+
+ E.g. app may fail to do a user-critical background job that may likely impact user's
+ safety/security/device accessibility.
+
+ This declaration may cause an additional review when publishing your app.
+
+ Apps with this declaration are exempt from auto revoke by default, though the user has the final say
+ in both revoking the permissions as well as the app's auto revoke exemption status. -->
<enum name="disallowed" value="2" />
</attr>
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b91d35b..003c0da 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3603,12 +3603,6 @@
<!-- Whether the device supports quick settings and its associated APIs -->
<bool name="config_quickSettingsSupported">true</bool>
- <!-- Comma separated list of extra quick settings tiles to be added to the default set as
- defined in SystemUi (com.android.systemui.R.string.quick_settings_tiles_default).
- Custom tiles (TileService) must be specified as "custom(pkg_name/class_in_package)"
- (without the quotes, both absolute and relative class works). -->
- <string name="config_defaultExtraQuickSettingsTiles" translatable="false"></string>
-
<!-- The component name, flattened to a string, for the default autofill service
to enabled for an user. This service must be trusted, as it can be activated
without explicit consent of the user. If no autofill service with the
@@ -3905,7 +3899,7 @@
<string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
- <bool name="config_swipe_up_gesture_setting_available">false</bool>
+ <bool name="config_swipe_up_gesture_setting_available">true</bool>
<!-- Applications which are disabled unless matching a particular sku -->
<string-array name="config_disableApksUnlessMatchedSku_apk_list" translatable="false" />
@@ -4427,4 +4421,8 @@
<!-- Set to true to make assistant show in front of the dream/screensaver. -->
<bool name="config_assistantOnTopOfDream">false</bool>
+ <!-- pdp data retry for cause 29, 33 and 55 -->
+ <bool name="config_pdp_reject_enable_retry">false</bool>
+ <!-- pdp data reject retry delay in ms -->
+ <integer name="config_pdp_reject_retry_delay_ms">-1</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bbe547b..2ac61ec 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -559,6 +559,10 @@
<dimen name="resolver_max_width">480dp</dimen>
+ <!-- Tile Stroke width -->
+ <dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
+ <dimen name="config_qsTileStrokeWidthInactive">-1dp</dimen>
+
<!-- Amount to reduce the size of the circular mask by (to compensate for
aliasing effects). This is only used on circular displays. -->
<dimen name="circular_display_mask_thickness">1px</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fb887c3..2869021 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2979,9 +2979,51 @@
<!-- @hide @SystemApi -->
<public type="color" name="system_notification_accent_color" id="0x0106001c" />
+ <!-- ===============================================================
+ Resources added in version R of the platform
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="importantForContentCapture" id="0x01010607" />
+ <public type="attr" name="forceQueryable" id="0x01010608"/>
+ <public type="attr" name="resourcesMap" id="0x01010609"/>
+ <public type="attr" name="animatedImageDrawable" id="0x0101060a"/>
+ <public type="attr" name="htmlDescription" id="0x0101060b"/>
+ <public type="attr" name="preferMinimalPostProcessing" id="0x0101060c"/>
+ <public type="attr" name="supportsInlineSuggestions" id="0x0101060d"/>
+ <public type="attr" name="crossProfile" id="0x0101060e"/>
+ <public type="attr" name="canTakeScreenshot" id="0x0101060f"/>
+ <!-- @hide @SystemApi -->
+ <public type="attr" name="sdkVersion" id="0x01010610" />
+ <!-- @hide @SystemApi -->
+ <public type="attr" name="minExtensionVersion" id="0x01010611" />
+ <public type="attr" name="allowNativeHeapPointerTagging" id="0x01010612" />
+ <public type="attr" name="autoRevokePermissions" id="0x01010613" />
+ <public type="attr" name="preserveLegacyExternalStorage" id="0x01010614" />
+ <public type="attr" name="mimeGroup" id="0x01010615" />
+ <public type="attr" name="gwpAsanMode" id="0x01010616" />
+
+ <!-- @hide @SystemApi -->
+ <public type="string" name="config_defaultCallRedirection" id="0x01040025" />
+ <!-- @hide @SystemApi -->
+ <public type="string" name="config_defaultCallScreening" id="0x01040026" />
+ <!-- @hide @SystemApi @TestApi -->
+ <public type="string" name="config_systemGallery" id="0x01040027" />
+
+ <public type="id" name="accessibilityActionPressAndHold" id="0x0102004a" />
+ <public type="id" name="accessibilitySystemActionBack" id="0x0102004b" />
+ <public type="id" name="accessibilitySystemActionHome" id="0x0102004c" />
+ <public type="id" name="accessibilitySystemActionRecents" id="0x0102004d" />
+ <public type="id" name="accessibilitySystemActionNotifications" id="0x0102004e" />
+ <public type="id" name="accessibilitySystemActionQuickSettings" id="0x0102004f" />
+ <public type="id" name="accessibilitySystemActionPowerDialog" id="0x01020050" />
+ <public type="id" name="accessibilitySystemActionToggleSplitScreen" id="0x01020051" />
+ <public type="id" name="accessibilitySystemActionLockScreen" id="0x01020052" />
+ <public type="id" name="accessibilitySystemActionTakeScreenshot" id="0x01020053" />
+ <public type="id" name="accessibilityActionImeEnter" id="0x01020054" />
<!-- ===============================================================
- Resources added in version R of the platform
+ Resources added in version S of the platform
NOTE: add <public> elements within a <public-group> like so:
@@ -2995,88 +3037,39 @@
value above is 0x01010530, so the public-group of attrs below has
the id value of 0x01010531.
=============================================================== -->
- <eat-comment />
- <public-group type="attr" first-id="0x01010607">
- <public name="importantForContentCapture" />
- <public name="forceQueryable" />
- <public name="resourcesMap" />
- <public name="animatedImageDrawable"/>
- <public name="htmlDescription"/>
- <public name="preferMinimalPostProcessing"/>
- <!-- @removed -->
- <public name="featureId" />
- <public name="supportsInlineSuggestions" />
- <public name="crossProfile" />
- <public name="canTakeScreenshot"/>
- <!-- @hide @SystemApi -->
- <public name="sdkVersion" />
- <!-- @hide @SystemApi -->
- <public name="minExtensionVersion" />
- <public name="allowNativeHeapPointerTagging" />
- <!-- @hide no longer used, kept to preserve padding -->
- <public name="allowAutoRevokePermissionsExemption"/>
- <public name="autoRevokePermissions" />
- <public name="preserveLegacyExternalStorage" />
- <public name="mimeGroup" />
- <public name="gwpAsanMode" />
- <!-- @hide -->
- <public name="scrollCaptureHint" />
- </public-group>
+ <public-group type="attr" first-id="0x01010617">
+ <!-- attribute definitions go here -->
+ </public-group>
- <public-group type="drawable" first-id="0x010800b5">
- </public-group>
+ <public-group type="drawable" first-id="0x010800b5">
+ <!-- drawable definitions go here -->
+ </public-group>
- <public-group type="style" first-id="0x010302e5">
- </public-group>
+ <public-group type="color" first-id="0x0106001d">
+ <!-- color definitions go here -->
+ </public-group>
- <public-group type="id" first-id="0x0102004a">
- <public name="accessibilityActionPressAndHold" />
- </public-group>
+ <public-group type="dimen" first-id="0x01050008">
+ <!-- dimension definitions go here -->
+ </public-group>
- <public-group type="string" first-id="0x01040025">
- <!-- @hide -->
- <public name="notification_channel_network_status" />
- <!-- @hide -->
- <public name="notification_channel_network_alerts" />
- <!-- @hide -->
- <public name="notification_channel_network_available" />
- <!-- @hide @SystemApi -->
- <public name="config_defaultCallRedirection" />
- <!-- @hide @SystemApi -->
- <public name="config_defaultCallScreening" />
- <!-- @hide @SystemApi @TestApi -->
- <public name="config_systemGallery" />
- </public-group>
+ <public-group type="bool" first-id="0x01110005">
+ <!-- boolean definitions go here -->
+ </public-group>
- <public-group type="bool" first-id="0x01110005">
- </public-group>
+ <public-group type="style" first-id="0x010302e5">
+ <!-- style definitions go here -->
+ </public-group>
- <public-group type="dimen" first-id="0x01050008">
- </public-group>
+ <public-group type="string" first-id="0x01040028">
+ <!-- string definitions go here -->
+ </public-group>
- <public-group type="color" first-id="0x0106001d">
- </public-group>
+ <public-group type="id" first-id="0x01020055">
+ <!-- id definitions go here -->
+ </public-group>
- <public-group type="id" first-id="0x0102004b">
- <public name="accessibilitySystemActionBack" />
- <public name="accessibilitySystemActionHome" />
- <public name="accessibilitySystemActionRecents" />
- <public name="accessibilitySystemActionNotifications" />
- <public name="accessibilitySystemActionQuickSettings" />
- <public name="accessibilitySystemActionPowerDialog" />
- <public name="accessibilitySystemActionToggleSplitScreen" />
- <public name="accessibilitySystemActionLockScreen" />
- <public name="accessibilitySystemActionTakeScreenshot" />
- <public name="accessibilityActionImeEnter" />
- </public-group>
-
- <public-group type="string" first-id="0x0104002c">
- <!-- @hide -->
- <public name="config_customMediaKeyDispatcher" />
- <!-- @hide -->
- <public name="config_customSessionPolicyProvider" />
- </public-group>
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
@@ -3085,4 +3078,5 @@
Items added outside of a group may have their value recalculated
every time something new is added to this file.
=============================================================== -->
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 33dd81d..35a7857 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5441,10 +5441,12 @@
<string name="accessibility_system_action_lock_screen_label">Lock Screen</string>
<!-- Label for taking screenshot action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_screenshot_label">Screenshot</string>
- <!-- Label for showing accessibility shortcut action [CHAR LIMIT=NONE] -->
- <string name="accessibility_system_action_accessibility_button_label">On-screen Accessibility Shortcut</string>
- <!-- Label for showing accessibility shortcut menu action [CHAR LIMIT=NONE] -->
- <string name="accessibility_system_action_accessibility_button_chooser_label">On-screen Accessibility Shortcut Chooser</string>
+ <!-- Label for triggering on-screen accessibility shortcut action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_label">On-screen Accessibility Shortcut</string>
+ <!-- Label for showing on-screen accessibility shortcut chooser action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label">On-screen Accessibility Shortcut Chooser</string>
+ <!-- Label for triggering hardware accessibility shortcut action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
<!-- Accessibility description of caption view -->
<string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
@@ -5745,4 +5747,13 @@
<string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS">IMPI unlock successful.</string>
<!-- Success message displayed on SIM NS_SP Depersonalization panel [CHAR LIMIT=none] -->
<string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS">Network subset service provider unlock successful.</string>
+
+ <!-- pdp data reject dialog string for cause 29, 33 and 55 [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_dialog_title"></string>
+ <!-- pdp data reject dialog string for cause 29 (USER_AUTHENTICATION) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_user_authentication_failed"></string>
+ <!-- pdp data reject dialog string for cause 33 (SERVICE_OPTION_NOT_SUBSCRIBED) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_service_not_subscribed"></string>
+ <!-- pdp data reject dialog string for cause 55 (MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED) [CHAR LIMIT=100] -->
+ <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed"></string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index bcce1f0..f920083 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -248,12 +248,6 @@
<item name="windowExitAnimation">@anim/fast_fade_out</item>
</style>
- <!-- Window animations for screen savers. {@hide} -->
- <style name="Animation.Dream">
- <item name="windowEnterAnimation">@anim/slow_fade_in</item>
- <item name="windowExitAnimation">@anim/fast_fade_out</item>
- </style>
-
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBar">
<item name="textAppearance">?attr/textAppearanceSmall</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 88161f6..9a7f07f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -361,6 +361,8 @@
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="dimen" name="config_highResTaskSnapshotScale" />
<java-symbol type="dimen" name="config_lowResTaskSnapshotScale" />
+ <java-symbol type="dimen" name="config_qsTileStrokeWidthInactive" />
+ <java-symbol type="dimen" name="config_qsTileStrokeWidthActive" />
<java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="string" name="config_recentsComponentName" />
@@ -1200,6 +1202,7 @@
<java-symbol type="string" name="personal_apps_suspension_title" />
<java-symbol type="string" name="personal_apps_suspension_tomorrow_text" />
<java-symbol type="string" name="personal_apps_suspension_text" />
+ <java-symbol type="string" name="personal_apps_suspended_turn_profile_on" />
<java-symbol type="string" name="factory_reset_warning" />
<java-symbol type="string" name="factory_reset_message" />
<java-symbol type="string" name="lockscreen_transport_play_description" />
@@ -1579,7 +1582,6 @@
<java-symbol type="style" name="Animation.Tooltip" />
<java-symbol type="style" name="Animation.TypingFilter" />
<java-symbol type="style" name="Animation.TypingFilterRestore" />
- <java-symbol type="style" name="Animation.Dream" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.Alert" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
<java-symbol type="style" name="Theme.Dialog.Alert" />
@@ -1824,6 +1826,9 @@
<java-symbol type="anim" name="rotation_animation_jump_exit" />
<java-symbol type="anim" name="rotation_animation_xfade_exit" />
<java-symbol type="anim" name="rotation_animation_enter" />
+ <java-symbol type="anim" name="dream_activity_open_exit" />
+ <java-symbol type="anim" name="dream_activity_open_enter" />
+ <java-symbol type="anim" name="dream_activity_close_exit" />
<java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
@@ -3446,7 +3451,6 @@
<java-symbol type="string" name="etws_primary_default_message_others" />
<java-symbol type="bool" name="config_quickSettingsSupported" />
- <java-symbol type="string" name="config_defaultExtraQuickSettingsTiles" />
<java-symbol type="style" name="Theme.DeviceDefault.QuickSettings" />
@@ -3843,8 +3847,9 @@
<java-symbol type="string" name="accessibility_system_action_quick_settings_label" />
<java-symbol type="string" name="accessibility_system_action_recents_label" />
<java-symbol type="string" name="accessibility_system_action_screenshot_label" />
- <java-symbol type="string" name="accessibility_system_action_accessibility_button_label" />
- <java-symbol type="string" name="accessibility_system_action_accessibility_button_chooser_label" />
+ <java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_label" />
+ <java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
+ <java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_freeform_caption" />
@@ -3993,4 +3998,16 @@
<java-symbol type="bool" name="config_assistantOnTopOfDream"/>
<java-symbol type="string" name="config_overrideComponentUiPackage" />
+
+ <java-symbol type="string" name="notification_channel_network_status" />
+ <java-symbol type="string" name="notification_channel_network_alerts" />
+ <java-symbol type="string" name="notification_channel_network_available" />
+
+ <!-- For Pdn throttle feature -->
+ <java-symbol type="bool" name="config_pdp_reject_enable_retry" />
+ <java-symbol type="integer" name="config_pdp_reject_retry_delay_ms" />
+ <java-symbol type="string" name="config_pdp_reject_dialog_title" />
+ <java-symbol type="string" name="config_pdp_reject_user_authentication_failed" />
+ <java-symbol type="string" name="config_pdp_reject_service_not_subscribed" />
+ <java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 88f9fc2..6e2995d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -704,6 +704,7 @@
<style name="Theme.Dream">
<item name="windowBackground">@color/black</item>
<item name="windowDisablePreview">true</item>
+ <item name="windowActivityTransitions">true</item>
</style>
<!-- Default theme for dialog windows and activities (on API level 10 and lower),
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 34417e6..a93dacf 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -44,8 +44,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
+import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
import android.view.Display;
import android.view.View;
@@ -367,6 +370,58 @@
}
@Test
+ public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final Configuration oldActivityConfig =
+ new Configuration(activity.getResources().getConfiguration());
+ final DisplayMetrics oldActivityMetrics = new DisplayMetrics();
+ activity.getDisplay().getMetrics(oldActivityMetrics);
+ final Resources oldAppResources = activity.getApplication().getResources();
+ final Configuration oldAppConfig =
+ new Configuration(oldAppResources.getConfiguration());
+ final DisplayMetrics oldApplicationMetrics = new DisplayMetrics();
+ oldApplicationMetrics.setTo(oldAppResources.getDisplayMetrics());
+ assertEquals("Process config must match the top activity config by default",
+ 0, oldActivityConfig.diffPublicOnly(oldAppConfig));
+ assertEquals("Process config must match the top activity config by default",
+ oldActivityMetrics, oldApplicationMetrics);
+
+ // Update the application configuration separately from activity config
+ final Configuration newAppConfig = new Configuration(oldAppConfig);
+ newAppConfig.densityDpi += 100;
+ newAppConfig.screenHeightDp += 100;
+ final Rect newBounds = new Rect(newAppConfig.windowConfiguration.getAppBounds());
+ newBounds.bottom += 100;
+ newAppConfig.windowConfiguration.setAppBounds(newBounds);
+ newAppConfig.windowConfiguration.setBounds(newBounds);
+ newAppConfig.seq++;
+
+ final ActivityThread activityThread = activity.getActivityThread();
+ activityThread.handleConfigurationChanged(newAppConfig);
+
+ // Verify that application config update was applied, but didn't change activity config.
+ assertEquals("Activity config must not change if the process config changes",
+ oldActivityConfig, activity.getResources().getConfiguration());
+
+ final DisplayMetrics newActivityMetrics = new DisplayMetrics();
+ activity.getDisplay().getMetrics(newActivityMetrics);
+ assertEquals("Activity display size must not change if the process config changes",
+ oldActivityMetrics, newActivityMetrics);
+ final Resources newAppResources = activity.getApplication().getResources();
+ assertEquals("Application config must be updated",
+ newAppConfig, newAppResources.getConfiguration());
+ final DisplayMetrics newApplicationMetrics = new DisplayMetrics();
+ newApplicationMetrics.setTo(newAppResources.getDisplayMetrics());
+ assertNotEquals("Application display size must be updated after config update",
+ oldApplicationMetrics, newApplicationMetrics);
+ assertNotEquals("Application display size must be updated after config update",
+ newActivityMetrics, newApplicationMetrics);
+ });
+ }
+
+ @Test
public void testResumeAfterNewIntent() {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final ActivityThread activityThread = activity.getActivityThread();
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 4b29d59..107fe3f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -198,21 +198,6 @@
}
@Test
- public void testRecycleMultiWindowModeChangeItem() {
- MultiWindowModeChangeItem emptyItem = MultiWindowModeChangeItem.obtain(false, null);
- MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(true, config());
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- MultiWindowModeChangeItem item2 = MultiWindowModeChangeItem.obtain(true, config());
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
public void testRecycleNewIntentItem() {
NewIntentItem emptyItem = NewIntentItem.obtain(null, false);
NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false);
@@ -243,21 +228,6 @@
}
@Test
- public void testRecyclePipModeChangeItem() {
- PipModeChangeItem emptyItem = PipModeChangeItem.obtain(false, null);
- PipModeChangeItem item = PipModeChangeItem.obtain(true, config());
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- PipModeChangeItem item2 = PipModeChangeItem.obtain(true, config());
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
public void testRecycleResumeActivityItem() {
ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false);
ResumeActivityItem item = ResumeActivityItem.obtain(3, true);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 3766cf7..47f9323 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -153,34 +153,6 @@
}
@Test
- public void testPipModeChange() {
- // Write to parcel
- PipModeChangeItem item = PipModeChangeItem.obtain(true /* isInPipMode */, config());
- writeAndPrepareForReading(item);
-
- // Read from parcel and assert
- PipModeChangeItem result = PipModeChangeItem.CREATOR.createFromParcel(mParcel);
-
- assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
- }
-
- @Test
- public void testMultiWindowModeChange() {
- // Write to parcel
- MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(
- true /* isInMultiWindowMode */, config());
- writeAndPrepareForReading(item);
-
- // Read from parcel and assert
- MultiWindowModeChangeItem result =
- MultiWindowModeChangeItem.CREATOR.createFromParcel(mParcel);
-
- assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
- }
-
- @Test
public void testDestroy() {
DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */,
135 /* configChanges */);
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 567552f..0490678 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -35,6 +35,9 @@
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
@@ -300,7 +303,8 @@
final Intent result = localReceiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_SUCCESS);
- assertEquals(expectedResult, status);
+ String statusMessage = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ assertEquals(statusMessage, expectedResult, status);
} catch (IllegalArgumentException | IOException | RemoteException e) {
Log.w(TAG, "Failed to install package; path=" + inPath, e);
fail("Failed to install package; path=" + inPath + ", e=" + e);
@@ -327,13 +331,14 @@
return Uri.fromFile(outFile);
}
- private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
+ private ParsingPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- PackageParser packageParser = new PackageParser();
- File sourceFile = new File(archiveFilePath);
- PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, 0);
- packageParser = null;
- return pkg;
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ new File(archiveFilePath), 0 /*flags*/, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ return result.getResult();
}
private boolean checkSd(long pkgLen) {
@@ -417,9 +422,9 @@
return INSTALL_LOC_ERR;
}
- private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) {
+ private void assertInstall(ParsingPackage pkg, int flags, int expInstallLocation) {
try {
- String pkgName = pkg.packageName;
+ String pkgName = pkg.getPackageName();
ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
assertNotNull(info);
assertEquals(pkgName, info.packageName);
@@ -565,20 +570,20 @@
class InstallParams {
Uri packageURI;
- PackageParser.Package pkg;
+ ParsingPackage pkg;
InstallParams(String outFileName, int rawResId) throws PackageParserException {
this.pkg = getParsedPackage(outFileName, rawResId);
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
}
- InstallParams(PackageParser.Package pkg) {
- this.packageURI = Uri.fromFile(new File(pkg.codePath));
+ InstallParams(ParsingPackage pkg) {
+ this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
this.pkg = pkg;
}
long getApkSize() {
- File file = new File(pkg.codePath);
+ File file = new File(pkg.getCodePath());
return file.length();
}
}
@@ -680,14 +685,12 @@
}
}
- private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
- throws PackageParserException {
+ private ParsingPackage getParsedPackage(String outFileName, int rawResId) {
PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
- return pkg;
+ return parsePackage(packageURI);
}
/*
@@ -698,15 +701,15 @@
private void installFromRawResource(InstallParams ip, int flags, boolean cleanUp, boolean fail,
int result, int expInstallLocation) throws Exception {
PackageManager pm = mContext.getPackageManager();
- PackageParser.Package pkg = ip.pkg;
+ ParsingPackage pkg = ip.pkg;
Uri packageURI = ip.packageURI;
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
// Make sure the package doesn't exist
try {
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
- GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
- invokeDeletePackage(pkg.packageName, 0, receiver);
+ GenericReceiver receiver = new DeleteReceiver(pkg.getPackageName());
+ invokeDeletePackage(pkg.getPackageName(), 0, receiver);
} catch (IllegalArgumentException | NameNotFoundException e) {
}
}
@@ -714,10 +717,10 @@
if (fail) {
invokeInstallPackageFail(packageURI, flags, result);
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
- assertNotInstalled(pkg.packageName);
+ assertNotInstalled(pkg.getPackageName());
}
} else {
- InstallReceiver receiver = new InstallReceiver(pkg.packageName);
+ InstallReceiver receiver = new InstallReceiver(pkg.getPackageName());
invokeInstallPackage(packageURI, flags, receiver, true);
// Verify installed information
assertInstall(pkg, flags, expInstallLocation);
@@ -818,15 +821,15 @@
Log.i(TAG, "replace=" + replace);
GenericReceiver receiver;
if (replace) {
- receiver = new ReplaceReceiver(ip.pkg.packageName);
+ receiver = new ReplaceReceiver(ip.pkg.getPackageName());
Log.i(TAG, "Creating replaceReceiver");
} else {
- receiver = new InstallReceiver(ip.pkg.packageName);
+ receiver = new InstallReceiver(ip.pkg.getPackageName());
}
try {
invokeInstallPackage(ip.packageURI, flags, receiver, true);
if (replace) {
- assertInstall(ip.pkg, flags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, flags, ip.pkg.getInstallLocation());
}
} finally {
cleanUpInstall(ip);
@@ -957,20 +960,20 @@
public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
InstallParams ip = sampleInstallFromRawResource(iFlags, false);
boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- assertTrue(invokeDeletePackage(ip.pkg.packageName, dFlags, receiver));
+ assertTrue(invokeDeletePackage(ip.pkg.getPackageName(), dFlags, receiver));
ApplicationInfo info = null;
Log.i(TAG, "okay4");
try {
- info = getPm().getApplicationInfo(ip.pkg.packageName,
+ info = getPm().getApplicationInfo(ip.pkg.getPackageName(),
PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
info = null;
}
if (retainData) {
assertNotNull(info);
- assertEquals(info.packageName, ip.pkg.packageName);
+ assertEquals(info.packageName, ip.pkg.getPackageName());
} else {
assertNull(info);
}
@@ -998,9 +1001,9 @@
}
Runtime.getRuntime().gc();
try {
- cleanUpInstall(ip.pkg.packageName);
+ cleanUpInstall(ip.pkg.getPackageName());
} finally {
- File outFile = new File(ip.pkg.codePath);
+ File outFile = new File(ip.pkg.getCodePath());
if (outFile != null && outFile.exists()) {
outFile.delete();
}
@@ -1070,13 +1073,13 @@
InstallParams ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new ReplaceReceiver(ip.pkg.getPackageName());
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, rp.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1103,7 +1106,7 @@
InstallParams rp = installFromRawResource("install.apk", rApk,
replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
- assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation);
+ assertInstall(rp.pkg, replaceFlags, ip.pkg.getInstallLocation());
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -1204,18 +1207,18 @@
// Install first
ip = installFromRawResource("install.apk", rawResId, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo oldAppInfo = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
if (fail) {
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull(info);
assertEquals(oldAppInfo.flags, info.flags);
} else {
// Create receiver based on expRetCode
- MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
- boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags, receiver);
+ MoveReceiver receiver = new MoveReceiver(ip.pkg.getPackageName());
+ boolean retCode = invokeMovePackage(ip.pkg.getPackageName(), moveFlags, receiver);
assertTrue(retCode);
- ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+ ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.getPackageName(), 0);
assertNotNull("ApplicationInfo for recently installed application should exist",
info);
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
@@ -1294,9 +1297,9 @@
ip = installFromRawResource("install.apk", R.raw.install, installFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
// Delete the package now retaining data.
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
- assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
+ assertTrue(invokeMovePackageFail(ip.pkg.getPackageName(), moveFlags, result));
} catch (Exception e) {
failStr(e);
} finally {
@@ -1712,7 +1715,7 @@
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
// **: Upon installing package, are its permissions granted?
@@ -1722,15 +1725,15 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon removing but not deleting, are permissions retained?
- GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
+ GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
try {
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
} catch (Exception e) {
failStr(e);
}
@@ -1742,14 +1745,14 @@
ip = installFromRawResource("install.apk", iApk,
iFlags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_USED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1759,9 +1762,9 @@
// **: Delete package using permissions; nothing to check here.
- GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.packageName);
+ GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.getPackageName());
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1772,7 +1775,7 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon installing declaring package, are sig permissions granted
@@ -1781,7 +1784,7 @@
ip = installFromRawResource("install.apk", iApk,
iFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+ assertInstall(ip.pkg, iFlags, ip.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_DEFINED);
assertPermissions(BASE_PERMISSIONS_SIGUSED);
@@ -1790,13 +1793,13 @@
ip2 = installFromRawResource("install2.apk", i2Apk,
i2Flags | PackageManager.INSTALL_REPLACE_EXISTING, false,
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
- assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation);
+ assertInstall(ip2.pkg, i2Flags, ip2.pkg.getInstallLocation());
assertPermissions(BASE_PERMISSIONS_NOTUSED);
// **: Upon deleting package, are all permissions removed?
try {
- invokeDeletePackage(ip.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip.pkg.getPackageName(), 0, receiver);
ip = null;
} catch (Exception e) {
failStr(e);
@@ -1807,7 +1810,7 @@
// **: Delete package using permissions; nothing to check here.
try {
- invokeDeletePackage(ip2.pkg.packageName, 0, receiver);
+ invokeDeletePackage(ip2.pkg.getPackageName(), 0, receiver);
ip2 = null;
} catch (Exception e) {
failStr(e);
@@ -1862,7 +1865,7 @@
int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
try {
InstallParams ip = installFromRawResource(apk1Name, apk1, 0, false,
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
@@ -1873,7 +1876,7 @@
failStr(e.getMessage());
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
+ cleanUpInstall(pkg1.getPackageName());
}
}
return null;
@@ -2460,16 +2463,16 @@
File outFile = new File(filesDir, apk2Name);
int rawResId = apk2;
Uri packageURI = getInstallablePackage(rawResId, outFile);
- PackageParser.Package pkg = parsePackage(packageURI);
+ ParsingPackage pkg = parsePackage(packageURI);
try {
- getPi().uninstall(pkg.packageName,
+ getPi().uninstall(pkg.getPackageName(),
PackageManager.DELETE_ALL_USERS,
null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip.pkg.packageName, pkg.packageName);
+ ip.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
cleanUpInstall(ip);
@@ -2530,13 +2533,13 @@
int retCode, int expMatchResult) throws Exception {
String apk1Name = "install1.apk";
String apk2Name = "install2.apk";
- PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
- PackageParser.Package pkg2 = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg1 = getParsedPackage(apk1Name, apk1);
+ ParsingPackage pkg2 = getParsedPackage(apk2Name, apk2);
try {
// Clean up before testing first.
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
installFromRawResource(apk1Name, apk1, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
if (fail) {
@@ -2545,14 +2548,23 @@
} else {
installFromRawResource(apk2Name, apk2, 0, false, false, -1,
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
- int match = mContext.getPackageManager().checkSignatures(pkg1.packageName,
- pkg2.packageName);
- assertEquals(expMatchResult, match);
+ // TODO: All checkSignatures tests should return the same result regardless of
+ // querying by package name or uid; however if there are any edge cases where
+ // individual packages within a shareduid are compared with signatures that do not
+ // match the full lineage of the shareduid this method should be overloaded to
+ // accept the expected response for the uid query.
+ PackageManager pm = getPm();
+ int matchByName = pm.checkSignatures(pkg1.getPackageName(), pkg2.getPackageName());
+ int pkg1Uid = pm.getApplicationInfo(pkg1.getPackageName(), 0).uid;
+ int pkg2Uid = pm.getApplicationInfo(pkg2.getPackageName(), 0).uid;
+ int matchByUid = pm.checkSignatures(pkg1Uid, pkg2Uid);
+ assertEquals(expMatchResult, matchByName);
+ assertEquals(expMatchResult, matchByUid);
}
} finally {
if (cleanUp) {
- cleanUpInstall(pkg1.packageName);
- cleanUpInstall(pkg2.packageName);
+ cleanUpInstall(pkg1.getPackageName());
+ cleanUpInstall(pkg2.getPackageName());
}
}
}
@@ -2618,15 +2630,15 @@
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
PackageManager pm = mContext.getPackageManager();
// Delete app2
- PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
+ ParsingPackage pkg = getParsedPackage(apk2Name, apk2);
try {
- getPi().uninstall(
- pkg.packageName, PackageManager.DELETE_ALL_USERS, null /*statusReceiver*/);
+ getPi().uninstall(pkg.getPackageName(), PackageManager.DELETE_ALL_USERS,
+ null /*statusReceiver*/);
} catch (IllegalArgumentException ignore) {
}
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
- ip1.pkg.packageName, pkg.packageName);
+ ip1.pkg.getPackageName(), pkg.getPackageName());
assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, match);
} finally {
if (ip1 != null) {
@@ -2831,8 +2843,8 @@
PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
try {
// then, remove it, keeping it's data around
- final GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
+ final GenericReceiver receiver = new DeleteReceiver(ip.pkg.getPackageName());
+ invokeDeletePackage(ip.pkg.getPackageName(), PackageManager.DELETE_KEEP_DATA, receiver);
final List<PackageInfo> packages = getPm().getInstalledPackages(flags);
assertNotNull("installed packages cannot be null", packages);
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 164c372..bfcf52a 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -100,12 +100,12 @@
// test if setVisibility can show IME
mImeConsumer.onWindowFocusGained();
mImeConsumer.applyImeVisibility(true);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test if setVisibility can hide IME
mImeConsumer.applyImeVisibility(false);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index cc85332..d4c2569 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -245,14 +245,14 @@
mController.applyImeVisibility(true /* setVisible */);
mController.show(Type.all());
// quickly jump to final state by cancelling it.
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false /* setVisible */);
mController.hide(Type.all());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -268,10 +268,10 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.applyImeVisibility(true);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.applyImeVisibility(false);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
@@ -291,7 +291,7 @@
mController.hide(types);
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
@@ -302,7 +302,7 @@
mController.show(types);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -321,21 +321,21 @@
int types = Type.navigationBars() | Type.systemBars();
// test show select types.
mController.show(types);
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test hide all
mController.hide(Type.all());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
// test single show
mController.show(Type.navigationBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -363,7 +363,7 @@
mController.hide(Type.systemBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -372,7 +372,7 @@
mController.show(Type.systemBars());
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -383,7 +383,7 @@
mController.hide(Type.navigationBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -391,7 +391,7 @@
mController.hide(Type.systemBars());
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -411,13 +411,13 @@
// show two at a time and hide one by one.
mController.show(types);
mController.hide(Type.navigationBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
mController.hide(Type.systemBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
@@ -431,7 +431,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.hide(Type.statusBars());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
@@ -446,7 +446,7 @@
// Gaining control
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
});
@@ -468,7 +468,7 @@
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
@@ -489,7 +489,7 @@
mController.show(ime(), true /* fromIme */);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
@@ -658,7 +658,7 @@
mController.getState().getSource(ITYPE_IME).getFrame());
assertNotEquals(new Rect(4, 5, 6, 7),
mController.getState().getSource(ITYPE_IME).getVisibleFrame());
- mController.cancelExistingAnimation();
+ mController.cancelExistingAnimations();
assertEquals(new Rect(0, 1, 2, 3),
mController.getState().getSource(ITYPE_IME).getFrame());
assertEquals(new Rect(4, 5, 6, 7),
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java b/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java
new file mode 100644
index 0000000..6b62635
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class ConversationActionTest {
+
+ @Test
+ public void toBuilder() {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final PendingIntent intent = PendingIntent.getActivity(context, 0, new Intent(), 0);
+ final Icon icon = Icon.createWithData(new byte[]{0}, 0, 1);
+ final Bundle extras = new Bundle();
+ extras.putInt("key", 5);
+ final ConversationAction convAction =
+ new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+ .setAction(new RemoteAction(icon, "title", "descr", intent))
+ .setConfidenceScore(0.5f)
+ .setExtras(extras)
+ .build();
+
+ final ConversationAction fromBuilder = convAction.toBuilder().build();
+
+ assertThat(fromBuilder.getType()).isEqualTo(convAction.getType());
+ assertThat(fromBuilder.getAction()).isEqualTo(convAction.getAction());
+ assertThat(fromBuilder.getConfidenceScore()).isEqualTo(convAction.getConfidenceScore());
+ assertThat(fromBuilder.getExtras()).isEqualTo(convAction.getExtras());
+ assertThat(fromBuilder.getTextReply()).isEqualTo(convAction.getTextReply());
+ }
+
+ @Test
+ public void toBuilder_textReply() {
+ final ConversationAction convAction =
+ new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
+ .setTextReply(":P")
+ .build();
+
+ final ConversationAction fromBuilder = convAction.toBuilder().build();
+
+ assertThat(fromBuilder.getTextReply()).isEqualTo(convAction.getTextReply());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index 39ededa..cf742b0 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -57,6 +57,7 @@
static {
BUNDLE.putString(BUNDLE_KEY, BUNDLE_VALUE);
}
+ private static final float EPSILON = 1e-7f;
public Icon generateTestIcon(int width, int height, int colorValue) {
final int numPixels = width * height;
@@ -128,8 +129,8 @@
assertEquals(2, result.getEntityCount());
assertEquals(TextClassifier.TYPE_PHONE, result.getEntity(0));
assertEquals(TextClassifier.TYPE_ADDRESS, result.getEntity(1));
- assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
- assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+ assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), EPSILON);
+ assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), EPSILON);
// Extras
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
@@ -226,4 +227,45 @@
assertEquals(1, resultSystemTcMetadata.getUserId());
assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
}
+
+ @Test
+ public void testToBuilder() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ final Icon icon1 = generateTestIcon(5, 5, Color.RED);
+ final Icon icon2 = generateTestIcon(2, 10, Color.BLUE);
+ final TextClassification classification = new TextClassification.Builder()
+ .setIcon(icon1.loadDrawable(context))
+ .setLabel("label")
+ .setIntent(new Intent("action"))
+ .setOnClickListener(view -> { })
+ .addAction(new RemoteAction(icon1, "title1", "desc1",
+ PendingIntent.getActivity(context, 0, new Intent("action1"), 0)))
+ .addAction(new RemoteAction(icon1, "title2", "desc2",
+ PendingIntent.getActivity(context, 0, new Intent("action2"), 0)))
+ .setEntityType(TextClassifier.TYPE_EMAIL, 0.5f)
+ .setEntityType(TextClassifier.TYPE_PHONE, 0.4f)
+ .build();
+
+ final TextClassification fromBuilder = classification.toBuilder().build();
+
+ assertEquals(classification.getId(), fromBuilder.getId());
+ assertEquals(classification.getText(), fromBuilder.getText());
+ assertEquals(classification.getIcon(), fromBuilder.getIcon());
+ assertEquals(classification.getLabel(), fromBuilder.getLabel());
+ assertEquals(classification.getIntent(), fromBuilder.getIntent());
+ assertEquals(classification.getOnClickListener(), fromBuilder.getOnClickListener());
+ assertEquals(classification.getExtras(), fromBuilder.getExtras());
+ assertEquals(classification.getActions(), fromBuilder.getActions());
+ assertEquals(classification.getEntityCount(), fromBuilder.getEntityCount());
+ assertEquals(classification.getEntity(0), fromBuilder.getEntity(0));
+ assertEquals(classification.getEntity(1), fromBuilder.getEntity(1));
+ assertEquals(
+ classification.getConfidenceScore(TextClassifier.TYPE_EMAIL),
+ fromBuilder.getConfidenceScore(TextClassifier.TYPE_EMAIL),
+ EPSILON);
+ assertEquals(
+ classification.getConfidenceScore(TextClassifier.TYPE_PHONE),
+ fromBuilder.getConfidenceScore(TextClassifier.TYPE_PHONE),
+ EPSILON);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 80fb358..e23a3ca 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1763,7 +1763,8 @@
Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
- Intent chooserIntent = createChooserIntent(new Intent[] {new Intent("action.fake")});
+ Intent chooserIntent = createChooserIntent(createSendTextIntent(),
+ new Intent[] {new Intent("action.fake")});
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
chosen[0] = targetInfo.getResolveInfo();
@@ -1796,7 +1797,7 @@
new Intent("action.fake1"),
new Intent("action.fake2")
};
- Intent chooserIntent = createChooserIntent(initialIntents);
+ Intent chooserIntent = createChooserIntent(createSendTextIntent(), initialIntents);
sOverrides.packageManager = mock(PackageManager.class);
when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
.thenReturn(createFakeResolveInfo());
@@ -1809,12 +1810,74 @@
assertThat(activity.getWorkListAdapter().getCallerTargetCount(), is(0));
}
- private Intent createChooserIntent(Intent[] initialIntents) {
+ @Test
+ public void testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ int workProfileTargets = 4;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(workProfileTargets);
+ sOverrides.hasCrossProfileIntents = false;
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent[] initialIntents = {
+ new Intent("action.fake1"),
+ new Intent("action.fake2")
+ };
+ Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
+ sOverrides.packageManager = mock(PackageManager.class);
+ when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(createFakeResolveInfo());
+
+ final ChooserWrapperActivity activity = mActivityRule.launchActivity(chooserIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+
+ onView(withText(R.string.resolver_cant_access_work_apps))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent[] initialIntents = {
+ new Intent("action.fake1"),
+ new Intent("action.fake2")
+ };
+ Intent chooserIntent = createChooserIntent(new Intent(), initialIntents);
+ sOverrides.packageManager = mock(PackageManager.class);
+ when(sOverrides.packageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(createFakeResolveInfo());
+
+ mActivityRule.launchActivity(chooserIntent);
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ onView(withText(R.string.resolver_no_work_apps_available_resolve))
+ .check(matches(isDisplayed()));
+ }
+
+ private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
Intent chooserIntent = new Intent();
chooserIntent.setAction(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title");
- chooserIntent.putExtra(Intent.EXTRA_INTENT, createSendTextIntent());
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
chooserIntent.setType("text/plain");
if (initialIntents != null) {
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents);
diff --git a/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
index 8e4f38e..35c5681 100644
--- a/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
@@ -16,9 +16,13 @@
package com.android.internal.util;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.os.Binder;
import android.os.Bundle;
import androidx.test.filters.SmallTest;
@@ -110,4 +114,54 @@
bundle2.putInt("KEY", 22);
assertFalse(InlinePresentationStyleUtils.bundleEquals(bundle1, bundle2));
}
+
+ @Test
+ public void testFilterContentTypes_nullOrEmpty() {
+ InlinePresentationStyleUtils.filterContentTypes(null);
+ InlinePresentationStyleUtils.filterContentTypes(new Bundle());
+ }
+
+ @Test
+ public void testFilterContentTypes_basic() {
+ Bundle bundle = new Bundle();
+ bundle.putInt("int", 11);
+ bundle.putString("str", "test");
+ bundle.putString("null", null);
+
+ InlinePresentationStyleUtils.filterContentTypes(bundle);
+
+ assertEquals(11, bundle.getInt("int"));
+ assertEquals("test", bundle.getString("str"));
+ assertTrue(bundle.keySet().contains("null"));
+ }
+
+ @Test
+ public void testFilterContentTypes_binder_removedBinder() {
+ Bundle bundle = new Bundle();
+ bundle.putInt("int", 11);
+ bundle.putString("str", "test");
+ bundle.putString("null", null);
+ bundle.putBinder("binder", new Binder());
+
+ InlinePresentationStyleUtils.filterContentTypes(bundle);
+
+ assertEquals(11, bundle.getInt("int"));
+ assertEquals("test", bundle.getString("str"));
+ assertTrue(bundle.keySet().contains("null"));
+ assertNull(bundle.getBinder("binder"));
+ }
+
+ @Test
+ public void testFilterContentTypes_binderInChild_removedBinder() {
+ Bundle child = new Bundle();
+ child.putBinder("binder", new Binder());
+ Bundle bundle = new Bundle();
+ bundle.putBundle("child", child);
+
+ InlinePresentationStyleUtils.filterContentTypes(bundle);
+
+ Bundle child2 = bundle.getBundle("child");
+ assertNotNull(child2);
+ assertNull(child2.getBinder("binder"));
+ }
}
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index efe658a..7292e07 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -19,6 +19,7 @@
<permission name="android.permission.ACCESS_NETWORK_STATE"/>
<permission name="android.permission.ACCESS_WIFI_STATE"/>
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.INJECT_EVENTS"/>
<!-- use for CarServiceUnitTest and CarServiceTest -->
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
diff --git a/data/keyboards/Vendor_045e_Product_02a1.kl b/data/keyboards/Vendor_045e_Product_02a1.kl
new file mode 100644
index 0000000..0214361
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_02a1.kl
@@ -0,0 +1,55 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# XBox 360 Wireless Controller
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Button labeled as "BACK" (left-pointing triangle)
+key 314 BUTTON_SELECT
+
+# The branded "X" button in the center of the controller
+key 316 BUTTON_MODE
+
+# Button labeled as "START" (right-pointing triangle)
+key 315 BUTTON_START
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
new file mode 100644
index 0000000..098f4bf
--- /dev/null
+++ b/errorprone/Android.bp
@@ -0,0 +1,23 @@
+
+java_plugin {
+ name: "error_prone_android_framework",
+
+ static_libs: [
+ "error_prone_android_framework_lib",
+ ],
+}
+
+java_library_host {
+ name: "error_prone_android_framework_lib",
+
+ srcs: ["java/**/*.java"],
+
+ static_libs: [
+ "//external/error_prone:error_prone_core",
+ "//external/dagger2:dagger2-auto-service",
+ ],
+
+ plugins: [
+ "//external/dagger2:dagger2-auto-service",
+ ],
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
new file mode 100644
index 0000000..48123ab
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.enclosingClass;
+import static com.google.errorprone.matchers.Matchers.hasAnnotation;
+import static com.google.errorprone.matchers.Matchers.instanceMethod;
+import static com.google.errorprone.matchers.Matchers.isSameType;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.throwStatement;
+import static com.google.errorprone.matchers.Matchers.variableType;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.CatchTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.CatchTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+
+import java.util.List;
+
+/**
+ * Apps making calls into the system server may end up persisting internal state
+ * or making security decisions based on the perceived success or failure of a
+ * call, or any default values returned. For this reason, we want to strongly
+ * throw when there was trouble with the transaction.
+ * <p>
+ * The rethrowFromSystemServer() method is the best-practice way of doing this
+ * correctly, so that we don't clutter logs with misleading stack traces, and
+ * this checker verifies that best-practice is used.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkRethrowFromSystem",
+ summary = "Verifies that system_server calls use rethrowFromSystemServer()",
+ severity = WARNING)
+public final class RethrowFromSystemChecker extends BugChecker implements CatchTreeMatcher {
+ private static final Matcher<Tree> INSIDE_MANAGER =
+ enclosingClass(hasAnnotation("android.annotation.SystemService"));
+ private static final Matcher<VariableTree> REMOTE_EXCEPTION = variableType(
+ isSameType("android.os.RemoteException"));
+ private static final Matcher<StatementTree> RETHROW_FROM_SYSTEM = throwStatement(
+ methodInvocation(instanceMethod().onExactClass("android.os.RemoteException")
+ .named("rethrowFromSystemServer")));
+
+ @Override
+ public Description matchCatch(CatchTree tree, VisitorState state) {
+ if (INSIDE_MANAGER.matches(tree, state)
+ && REMOTE_EXCEPTION.matches(tree.getParameter(), state)) {
+ final List<? extends StatementTree> statements = tree.getBlock().getStatements();
+ if (statements.size() != 1 || !RETHROW_FROM_SYSTEM.matches(statements.get(0), state)) {
+ return buildDescription(tree)
+ .setMessage("Must contain single "
+ + "'throw e.rethrowFromSystemServer()' statement")
+ .build();
+ }
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
new file mode 100644
index 0000000..232cf3f
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.anything;
+import static com.google.errorprone.matchers.Matchers.kindIs;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.FieldMatchers;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.BinaryTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.Tree.Kind;
+
+/**
+ * Over the years we've had several obscure bugs related to how SDK level
+ * comparisons are performed, specifically during the window of time where we've
+ * started distributing the "frankenbuild" to developers.
+ * <p>
+ * Consider the case where a framework developer shipping release "R" wants to
+ * only grant a specific behavior to modern apps; they could write this in two
+ * different ways:
+ * <ol>
+ * <li>if (targetSdkVersion > Build.VERSION_CODES.Q) {
+ * <li>if (targetSdkVersion >= Build.VERSION_CODES.R) {
+ * </ol>
+ * The safer of these two options is (2), which will ensure that developers only
+ * get the behavior when <em>both</em> the app and the platform agree on the
+ * specific SDK level having shipped.
+ * <p>
+ * Consider the breakage that would happen with option (1) if we started
+ * shipping APKs that are based on the final R SDK, but are then installed on
+ * earlier preview releases which still consider R to be CUR_DEVELOPMENT; they'd
+ * risk crashing due to behaviors that were never part of the official R SDK.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkTargetSdk",
+ summary = "Verifies that all target SDK comparisons are sane",
+ severity = WARNING)
+public final class TargetSdkChecker extends BugChecker implements BinaryTreeMatcher {
+ private static final Matcher<ExpressionTree> VERSION_CODE = FieldMatchers
+ .anyFieldInClass("android.os.Build.VERSION_CODES");
+
+ private static final Matcher<BinaryTree> INVALID_OLD_BEHAVIOR = anyOf(
+ allOf(kindIs(Kind.LESS_THAN_EQUAL), binaryTreeExact(anything(), VERSION_CODE)),
+ allOf(kindIs(Kind.GREATER_THAN_EQUAL), binaryTreeExact(VERSION_CODE, anything())));
+
+ private static final Matcher<BinaryTree> INVALID_NEW_BEHAVIOR = anyOf(
+ allOf(kindIs(Kind.GREATER_THAN), binaryTreeExact(anything(), VERSION_CODE)),
+ allOf(kindIs(Kind.LESS_THAN), binaryTreeExact(VERSION_CODE, anything())));
+
+ @Override
+ public Description matchBinary(BinaryTree tree, VisitorState state) {
+ if (INVALID_OLD_BEHAVIOR.matches(tree, state)) {
+ return buildDescription(tree)
+ .setMessage("Legacy behaviors must be written in style "
+ + "'targetSdk < Build.VERSION_CODES.Z'")
+ .build();
+ }
+ if (INVALID_NEW_BEHAVIOR.matches(tree, state)) {
+ return buildDescription(tree)
+ .setMessage("Modern behaviors must be written in style "
+ + "'targetSdk >= Build.VERSION_CODES.Z'")
+ .build();
+ }
+ return Description.NO_MATCH;
+ }
+
+ private static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
+ Matcher<ExpressionTree> right) {
+ return new Matcher<BinaryTree>() {
+ @Override
+ public boolean matches(BinaryTree tree, VisitorState state) {
+ return left.matches(tree.getLeftOperand(), state)
+ && right.matches(tree.getRightOperand(), state);
+ }
+ };
+ }
+}
diff --git a/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
new file mode 100644
index 0000000..46f0fb2
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2018 The Error Prone Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.matchers;
+
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.util.ASTHelpers;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.ImportTree;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import javax.annotation.Nullable;
+
+// TODO(glorioso): this likely wants to be a fluent interface like MethodMatchers.
+// Ex: [staticField()|instanceField()]
+// .[onClass(String)|onAnyClass|onClassMatching]
+// .[named(String)|withAnyName|withNameMatching]
+/** Static utility methods for creating {@link Matcher}s for detecting references to fields. */
+public final class FieldMatchers {
+ private FieldMatchers() {}
+
+ public static Matcher<ExpressionTree> anyFieldInClass(String className) {
+ return new FieldReferenceMatcher() {
+ @Override
+ boolean classIsAppropriate(ClassSymbol classSymbol) {
+ return classSymbol.getQualifiedName().contentEquals(className);
+ }
+
+ @Override
+ boolean fieldSymbolIsAppropriate(Symbol symbol) {
+ return true;
+ }
+ };
+ }
+
+ public static Matcher<ExpressionTree> staticField(String className, String fieldName) {
+ return new FieldReferenceMatcher() {
+ @Override
+ boolean classIsAppropriate(ClassSymbol classSymbol) {
+ return classSymbol.getQualifiedName().contentEquals(className);
+ }
+
+ @Override
+ boolean fieldSymbolIsAppropriate(Symbol symbol) {
+ return symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+ }
+ };
+ }
+
+ public static Matcher<ExpressionTree> instanceField(String className, String fieldName) {
+ return new FieldReferenceMatcher() {
+ @Override
+ boolean classIsAppropriate(ClassSymbol classSymbol) {
+ return classSymbol.getQualifiedName().contentEquals(className);
+ }
+
+ @Override
+ boolean fieldSymbolIsAppropriate(Symbol symbol) {
+ return !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
+ }
+ };
+ }
+
+ private abstract static class FieldReferenceMatcher implements Matcher<ExpressionTree> {
+ @Override
+ public boolean matches(ExpressionTree expressionTree, VisitorState state) {
+ return isSymbolFieldInAppropriateClass(ASTHelpers.getSymbol(expressionTree))
+ // Don't match if this is part of a static import tree, since they will get the finding
+ // on any usage of the field in their source.
+ && ASTHelpers.findEnclosingNode(state.getPath(), ImportTree.class) == null;
+ }
+
+ private boolean isSymbolFieldInAppropriateClass(@Nullable Symbol symbol) {
+ if (symbol == null) {
+ return false;
+ }
+ return symbol.getKind().isField()
+ && fieldSymbolIsAppropriate(symbol)
+ && classIsAppropriate(symbol.owner.enclClass());
+ }
+
+ abstract boolean fieldSymbolIsAppropriate(Symbol symbol);
+
+ abstract boolean classIsAppropriate(ClassSymbol classSymbol);
+ }
+}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 752695f..22f5489 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -998,7 +998,7 @@
* Sets the rotation value for the display list around the Z axis.
*
* @param rotation The rotation value of the display list, in degrees
- * @see View#setRotationZ(float)
+ * @see View#setRotation(float)
* @see #getRotationZ()
* @return True if the value changed, false if the new value was the same as the previous value.
*/
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e70529b..9cf12f1 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -617,7 +617,7 @@
* {@link #setTintList(ColorStateList) tint}.
* </p>
*
- * @see {@link #setColorFilter(ColorFilter)} }
+ * @see #setColorFilter(ColorFilter)
* @deprecated use {@link #setColorFilter(ColorFilter)} with an instance
* of {@link android.graphics.BlendModeColorFilter}
*/
diff --git a/graphics/java/android/graphics/fonts/FontStyle.java b/graphics/java/android/graphics/fonts/FontStyle.java
index af517d6..09799fd 100644
--- a/graphics/java/android/graphics/fonts/FontStyle.java
+++ b/graphics/java/android/graphics/fonts/FontStyle.java
@@ -217,7 +217,7 @@
/**
* Gets the weight value
*
- * @see FontStyle#setWeight(int)
+ * @see #FontStyle(int, int)
* @return a weight value
*/
public @IntRange(from = 0, to = 1000) int getWeight() {
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 54622c5..babcfc3 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -320,7 +320,7 @@
/**
* Returns the array of tab stops in pixels.
*
- * @see #setTabStops(float[], int)
+ * @see #setTabStops
*/
public @Nullable float[] getTabStops() {
return mVariableTabStops;
@@ -329,7 +329,7 @@
/**
* Returns the default tab stops in pixels.
*
- * @see #setTabStop(float[], int)
+ * @see #setTabStops
*/
public @Px @FloatRange(from = 0) float getDefaultTabStop() {
return mDefaultTabStop;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6761435..31e4555 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,7 +27,6 @@
#include "DamageAccumulator.h"
#include "pipeline/skia/SkiaDisplayList.h"
#endif
-#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
@@ -37,6 +36,7 @@
#include <atomic>
#include <sstream>
#include <string>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index d55e5b0..c0ec217 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -27,6 +27,8 @@
#include <androidfw/ResourceTypes.h>
+#include <ui/FatVector.h>
+
#include "AnimatorManager.h"
#include "CanvasTransform.h"
#include "Debug.h"
@@ -35,7 +37,6 @@
#include "RenderProperties.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
-#include "utils/FatVector.h"
#include <vector>
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5790150..9414379 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -789,9 +789,11 @@
xform[i - start].fTx = pos.x() - tan.y() * y - halfWidth * tan.x();
xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
}
- auto* finalCanvas = this->asSkCanvas();
+
+ sk_sp<SkTextBlob> textBlob(builder.make());
+
apply_looper(&paintCopy, [&](const SkPaint& p) {
- finalCanvas->drawTextBlob(builder.make(), 0, 0, paintCopy);
+ mCanvas->drawTextBlob(textBlob, 0, 0, p);
});
}
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index 0ce04a2..a2fef1e 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -29,9 +29,9 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
-#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
#include <minikin/LocaleList.h>
+#include <ui/FatVector.h>
#include <memory>
@@ -104,7 +104,7 @@
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint weight, jint italic) {
- uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 7e8f8d8..5714cd1 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -28,8 +28,8 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
-#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
+#include <ui/FatVector.h>
#include <memory>
@@ -93,7 +93,7 @@
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
- uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index cfc0f9b..d669f84 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -21,7 +21,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c19b187..335bcdc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,12 @@
if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ // Notify the callbacks, even if there's nothing to draw so they aren't waiting
+ // indefinitely
+ for (auto& func : mFrameCompleteCallbacks) {
+ std::invoke(func, mFrameNumber);
+ }
+ mFrameCompleteCallbacks.clear();
return;
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index cae3e3b..206b58f 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -27,7 +27,6 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
@@ -40,6 +39,8 @@
#include <utils/Mutex.h>
#include <thread>
+#include <ui/FatVector.h>
+
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index a5355fc..ba70afc 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,13 +23,13 @@
#include <GrContext.h>
#include <GrTypes.h>
#include <android/sync.h>
+#include <ui/FatVector.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/TraceUtils.h"
namespace android {
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 8523e6c..6585a62 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <utils/FatVector.h>
+#include <ui/FatVector.h>
#include <tests/common/TestUtils.h>
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
deleted file mode 100644
index 49f1984..0000000
--- a/libs/hwui/utils/FatVector.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_FAT_VECTOR_H
-#define ANDROID_FAT_VECTOR_H
-
-#include "utils/Macros.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <utils/Log.h>
-#include <type_traits>
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-template <typename T, size_t SIZE>
-class InlineStdAllocator {
-public:
- struct Allocation {
- PREVENT_COPY_AND_ASSIGN(Allocation);
-
- public:
- Allocation(){};
- // char array instead of T array, so memory is uninitialized, with no destructors run
- char array[sizeof(T) * SIZE];
- bool inUse = false;
- };
-
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
-
- explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
- InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
- ~InlineStdAllocator() {}
-
- T* allocate(size_t num, const void* = 0) {
- if (!mAllocation.inUse && num <= SIZE) {
- mAllocation.inUse = true;
- return (T*)mAllocation.array;
- } else {
- return (T*)malloc(num * sizeof(T));
- }
- }
-
- void deallocate(pointer p, size_t num) {
- if (p == (T*)mAllocation.array) {
- mAllocation.inUse = false;
- } else {
- // 'free' instead of delete here - destruction handled separately
- free(p);
- }
- }
- Allocation& mAllocation;
-};
-
-/**
- * std::vector with SIZE elements preallocated into an internal buffer.
- *
- * Useful for avoiding the cost of malloc in cases where only SIZE or
- * fewer elements are needed in the common case.
- */
-template <typename T, size_t SIZE>
-class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
-public:
- FatVector()
- : std::vector<T, InlineStdAllocator<T, SIZE>>(
- InlineStdAllocator<T, SIZE>(mAllocation)) {
- this->reserve(SIZE);
- }
-
- explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
-
-private:
- typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_FAT_VECTOR_H
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9b4aebc..a112bdd0 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1993,7 +1993,7 @@
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean registerGnssStatusCallback(@NonNull GnssStatus.Callback callback) {
- return registerGnssStatusCallback(Runnable::run, callback);
+ return registerGnssStatusCallback(callback, null);
}
/**
@@ -2954,10 +2954,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.unregisterGnssStatusCallback(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.unregisterGnssStatusCallback(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssStatusListener extends IGnssStatusListener.Stub {
@@ -3020,10 +3020,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssMeasurementsListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssMeasurementsListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
@Override
@@ -3073,10 +3073,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssNavigationMessageListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssNavigationMessageListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssNavigationMessageListener extends IGnssNavigationMessageListener.Stub {
@@ -3114,10 +3114,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssAntennaInfoListener(mListenerTransport);
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssAntennaInfoListener(mListenerTransport);
+ mListenerTransport = null;
+ }
}
private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub {
@@ -3151,10 +3151,10 @@
@Override
protected void unregisterService() throws RemoteException {
- Preconditions.checkState(mListenerTransport != null);
-
- mService.removeGnssBatchingCallback();
- mListenerTransport = null;
+ if (mListenerTransport != null) {
+ mService.removeGnssBatchingCallback();
+ mListenerTransport = null;
+ }
}
private class BatchedLocationCallback extends IBatchedLocationCallback.Stub {
diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java
index 4e70501..4c0850b 100644
--- a/media/java/android/media/AudioFocusRequest.java
+++ b/media/java/android/media/AudioFocusRequest.java
@@ -80,9 +80,9 @@
* <p>An {@code AudioFocusRequest} instance always contains one of the four types of requests
* explained above. It is passed when building an {@code AudioFocusRequest} instance with its
* builder in the {@link Builder} constructor
- * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(int)}, or
+ * {@link AudioFocusRequest.Builder#Builder(int)}, or
* with {@link AudioFocusRequest.Builder#setFocusGain(int)} after copying an existing instance with
- * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(AudioFocusRequest)}.
+ * {@link AudioFocusRequest.Builder#Builder(AudioFocusRequest)}.
*
* <h3>Qualifying your focus request</h3>
* <h4>Use case requiring a focus request</h4>
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index c91ff0d..ff9fd41 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -166,10 +166,25 @@
*
* A Boolean value which is true if Atmos is present in an E-AC3 stream.
*/
+
+ // Since Boolean isn't handled by Parceling, we translate
+ // internally to KEY_HAS_ATMOS when sending through JNI.
+ // Consider deprecating this key for KEY_HAS_ATMOS in the future.
+ //
@NonNull public static final Key<Boolean> KEY_ATMOS_PRESENT =
createKey("atmos-present", Boolean.class);
/**
+ * A key representing the presence of Atmos in an E-AC3 stream.
+ *
+ * An Integer value which is nonzero if Atmos is present in an E-AC3 stream.
+ * The integer representation is used for communication to the native side.
+ * @hide
+ */
+ @NonNull public static final Key<Integer> KEY_HAS_ATMOS =
+ createKey("has-atmos", Integer.class);
+
+ /**
* A key representing the audio encoding used for the stream.
* This is the same encoding used in {@link AudioFormat#getEncoding()}.
*
@@ -731,6 +746,15 @@
Log.e(TAG, "Failed to unpack value for map");
return null;
}
+
+ // Special handling of KEY_ATMOS_PRESENT.
+ if (key.equals(Format.KEY_HAS_ATMOS.getName())
+ && value.first == Format.KEY_HAS_ATMOS.getValueClass()) {
+ ret.set(Format.KEY_ATMOS_PRESENT,
+ (Boolean) ((int) value.second != 0)); // Translate Integer to Boolean
+ continue; // Should we store both keys in the java table?
+ }
+
ret.set(createKey(key, value.first), value.first.cast(value.second));
}
return ret;
@@ -746,11 +770,19 @@
return false;
}
for (Key<?> key : obj.keySet()) {
+ Object value = obj.get(key);
+
+ // Special handling of KEY_ATMOS_PRESENT.
+ if (key == Format.KEY_ATMOS_PRESENT) {
+ key = Format.KEY_HAS_ATMOS;
+ value = (Integer) ((boolean) value ? 1 : 0); // Translate Boolean to Integer
+ }
+
if (!strDataPackage.pack(output, key.getName())) {
Log.i(TAG, "Failed to pack key: " + key.getName());
return false;
}
- if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), obj.get(key)))) {
+ if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), value))) {
Log.i(TAG, "Failed to pack value: " + obj.get(key));
return false;
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1d229b80..9f3fc5d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1357,7 +1357,7 @@
* Can only be called only if the AudioTrack is opened in offload mode
* {@see Builder#setOffloadedPlayback(boolean)}.
* Can only be called only if the AudioTrack is in state {@link #PLAYSTATE_PLAYING}
- * {@see #getPlaystate()}.
+ * {@see #getPlayState()}.
* Use this method in the same thread as any write() operation.
*/
public void setOffloadEndOfStream() {
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 1617b87..559a61d 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -535,7 +535,7 @@
* if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
* be used to query the actual {@link Bitmap.Config}.
*
- * @see {@link #getFrameAtTime(long, int, BitmapParams)}
+ * @see #getFrameAtTime(long, int, BitmapParams)
*/
public @Nullable Bitmap getFrameAtTime(long timeUs, @Option int option) {
if (option < OPTION_PREVIOUS_SYNC ||
@@ -581,7 +581,7 @@
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
*
- * @see {@link #getFrameAtTime(long, int)}
+ * @see #getFrameAtTime(long, int)
*/
public @Nullable Bitmap getFrameAtTime(
long timeUs, @Option int option, @NonNull BitmapParams params) {
@@ -623,7 +623,7 @@
* be used to query the actual {@link Bitmap.Config}.
* @throws IllegalArgumentException if passed in invalid option or width by height
* is less than or equal to 0.
- * @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
+ * @see #getScaledFrameAtTime(long, int, int, int, BitmapParams)
*/
public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
@IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) {
@@ -668,7 +668,7 @@
* scaled video frame, which can be null, if such a frame cannot be retrieved.
* @throws IllegalArgumentException if passed in invalid option or width by height
* is less than or equal to 0.
- * @see {@link #getScaledFrameAtTime(long, int, int, int)}
+ * @see #getScaledFrameAtTime(long, int, int, int)
*/
public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
@IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight,
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 5d61dd0..0dc019c 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -171,8 +170,7 @@
public MediaController getMediaControllerForRoutingSession(
@NonNull RoutingSessionInfo sessionInfo) {
for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
- String volumeControlId = controller.getPlaybackInfo().getVolumeControlId();
- if (TextUtils.equals(sessionInfo.getId(), volumeControlId)) {
+ if (areSessionsMatched(controller, sessionInfo)) {
return controller;
}
}
@@ -207,6 +205,37 @@
}
/**
+ * Gets available routes for the given routing session.
+ * The returned routes can be passed to
+ * {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} for transferring the routing session.
+ *
+ * @param sessionInfo the routing session that would be transferred
+ */
+ @NonNull
+ public List<MediaRoute2Info> getAvailableRoutesForRoutingSession(
+ @NonNull RoutingSessionInfo sessionInfo) {
+ Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+ List<MediaRoute2Info> routes = new ArrayList<>();
+
+ String packageName = sessionInfo.getClientPackageName();
+ List<String> preferredFeatures = mPreferredFeaturesMap.get(packageName);
+ if (preferredFeatures == null) {
+ preferredFeatures = Collections.emptyList();
+ }
+ synchronized (mRoutesLock) {
+ for (MediaRoute2Info route : mRoutes.values()) {
+ if (route.isSystemRoute() || route.hasAnyFeatures(preferredFeatures)
+ || sessionInfo.getSelectedRoutes().contains(route.getId())
+ || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ routes.add(route);
+ }
+ }
+ }
+ return routes;
+ }
+
+ /**
* Gets the system routing session associated with no specific application.
*/
@NonNull
@@ -220,6 +249,33 @@
}
/**
+ * Gets the routing session of a media session.
+ * If the session is using {#link PlaybackInfo#PLAYBACK_TYPE_LOCAL local playback},
+ * the system routing session is returned.
+ * If the session is using {#link PlaybackInfo#PLAYBACK_TYPE_REMOTE remote playback},
+ * it returns the corresponding routing session or {@code null} if it's unavailable.
+ */
+ @Nullable
+ public RoutingSessionInfo getRoutingSessionForMediaController(MediaController mediaController) {
+ MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo();
+ if (playbackInfo == null) {
+ return null;
+ }
+ if (playbackInfo.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ return new RoutingSessionInfo.Builder(getSystemRoutingSession())
+ .setClientPackageName(mediaController.getPackageName())
+ .build();
+ }
+ for (RoutingSessionInfo sessionInfo : getActiveSessions()) {
+ if (!sessionInfo.isSystemSession()
+ && areSessionsMatched(mediaController, sessionInfo)) {
+ return sessionInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
* Gets routing sessions of an application with the given package name.
* The first element of the returned list is the system routing session.
*
@@ -344,14 +400,6 @@
/**
* Requests a volume change for a route asynchronously.
- */
- //TODO: remove this.
- public void requestSetVolume(MediaRoute2Info route, int volume) {
- setRouteVolume(route, volume);
- }
-
- /**
- * Requests a volume change for a route asynchronously.
* <p>
* It may have no effect if the route is currently not selected.
* </p>
@@ -576,30 +624,22 @@
}
for (CallbackRecord record : mCallbackRecords) {
record.mExecutor.execute(() -> record.mCallback
- .onControlCategoriesChanged(packageName, preferredFeatures));
- }
- for (CallbackRecord record : mCallbackRecords) {
- record.mExecutor.execute(() -> record.mCallback
.onPreferredFeaturesChanged(packageName, preferredFeatures));
}
}
/**
- * @hide
- */
- public RoutingController getControllerForSession(@NonNull RoutingSessionInfo sessionInfo) {
- return new RoutingController(sessionInfo);
- }
-
- /**
* Gets the unmodifiable list of selected routes for the session.
*/
@NonNull
public List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getSelectedRoutes();
- return getRoutesWithIds(routeIds);
+ synchronized (sLock) {
+ return sessionInfo.getSelectedRoutes().stream().map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -609,8 +649,15 @@
public List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getSelectableRoutes();
- return getRoutesWithIds(routeIds);
+ List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
+
+ synchronized (sLock) {
+ return sessionInfo.getSelectableRoutes().stream()
+ .filter(routeId -> !selectedRouteIds.contains(routeId))
+ .map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -620,8 +667,15 @@
public List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- List<String> routeIds = sessionInfo.getDeselectableRoutes();
- return getRoutesWithIds(routeIds);
+ List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
+
+ synchronized (sLock) {
+ return sessionInfo.getDeselectableRoutes().stream()
+ .filter(routeId -> selectedRouteIds.contains(routeId))
+ .map(mRoutes::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
/**
@@ -782,154 +836,25 @@
}
}
- private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) {
- synchronized (sLock) {
- return routeIds.stream().map(mRoutes::get)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
- }
- }
-
- //TODO: Remove this.
- /**
- * A class to control media routing session in media route provider.
- * With routing controller, an application can select a route into the session or deselect
- * a route in the session.
- */
- public final class RoutingController {
- private final Object mControllerLock = new Object();
- @GuardedBy("mControllerLock")
- private RoutingSessionInfo mSessionInfo;
-
- RoutingController(@NonNull RoutingSessionInfo sessionInfo) {
- mSessionInfo = sessionInfo;
+ private boolean areSessionsMatched(MediaController mediaController,
+ RoutingSessionInfo sessionInfo) {
+ MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo();
+ if (playbackInfo == null) {
+ return false;
}
- /**
- * Releases the session
- */
- public void release() {
- synchronized (mControllerLock) {
- releaseSession(mSessionInfo);
- }
+ String volumeControlId = playbackInfo.getVolumeControlId();
+ if (volumeControlId == null) {
+ return false;
}
- /**
- * Gets the ID of the session
- */
- @NonNull
- public String getSessionId() {
- synchronized (mControllerLock) {
- return mSessionInfo.getId();
- }
+ if (TextUtils.equals(volumeControlId, sessionInfo.getId())) {
+ return true;
}
-
- /**
- * Gets the client package name of the session
- */
- @NonNull
- public String getClientPackageName() {
- synchronized (mControllerLock) {
- return mSessionInfo.getClientPackageName();
- }
- }
-
- /**
- * @return the control hints used to control route session if available.
- */
- @Nullable
- public Bundle getControlHints() {
- synchronized (mControllerLock) {
- return mSessionInfo.getControlHints();
- }
- }
-
- /**
- * @return the unmodifiable list of currently selected routes
- */
- @NonNull
- public List<MediaRoute2Info> getSelectedRoutes() {
- return MediaRouter2Manager.this.getSelectedRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of selectable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getSelectableRoutes() {
- return MediaRouter2Manager.this.getSelectableRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of deselectable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getDeselectableRoutes() {
- return MediaRouter2Manager.this.getDeselectableRoutes(mSessionInfo);
- }
-
- /**
- * @return the unmodifiable list of transferable routes for the session.
- */
- @NonNull
- public List<MediaRoute2Info> getTransferableRoutes() {
- List<String> routeIds;
- synchronized (mControllerLock) {
- routeIds = mSessionInfo.getTransferableRoutes();
- }
- return getRoutesWithIds(routeIds);
- }
-
- /**
- * Selects a route for the remote session. The given route must satisfy all of the
- * following conditions:
- * <ul>
- * <li>ID should not be included in {@link #getSelectedRoutes()}</li>
- * <li>ID should be included in {@link #getSelectableRoutes()}</li>
- * </ul>
- * If the route doesn't meet any of above conditions, it will be ignored.
- *
- * @see #getSelectedRoutes()
- * @see #getSelectableRoutes()
- */
- public void selectRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.selectRoute(mSessionInfo, route);
- }
-
- /**
- * Deselects a route from the remote session. The given route must satisfy all of the
- * following conditions:
- * <ul>
- * <li>ID should be included in {@link #getSelectedRoutes()}</li>
- * <li>ID should be included in {@link #getDeselectableRoutes()}</li>
- * </ul>
- * If the route doesn't meet any of above conditions, it will be ignored.
- *
- * @see #getSelectedRoutes()
- * @see #getDeselectableRoutes()
- */
- public void deselectRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.deselectRoute(mSessionInfo, route);
- }
-
- /**
- * Transfers session to the given rotue.
- */
- public void transferToRoute(@NonNull MediaRoute2Info route) {
- MediaRouter2Manager.this.transferToRoute(mSessionInfo, route);
- }
-
- /**
- * Gets the session info of the session
- *
- * @hide
- */
- @NonNull
- public RoutingSessionInfo getSessionInfo() {
- synchronized (mControllerLock) {
- return mSessionInfo;
- }
- }
+ // Workaround for provider not being able to know the unique session ID.
+ return TextUtils.equals(volumeControlId, sessionInfo.getOriginalId())
+ && TextUtils.equals(mediaController.getPackageName(),
+ sessionInfo.getOwnerPackageName());
}
/**
@@ -976,16 +901,6 @@
public void onTransferFailed(@NonNull RoutingSessionInfo session,
@NonNull MediaRoute2Info route) { }
- //TODO: Remove this.
- /**
- * Called when the preferred route features of an app is changed.
- *
- * @param packageName the package name of the application
- * @param preferredFeatures the list of preferred route features set by an application.
- */
- public void onControlCategoriesChanged(@NonNull String packageName,
- @NonNull List<String> preferredFeatures) {}
-
/**
* Called when the preferred route features of an app is changed.
*
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 608e29a..edf1fc5 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -50,6 +50,7 @@
final String mId;
final CharSequence mName;
+ final String mOwnerPackageName;
final String mClientPackageName;
@Nullable
final String mProviderId;
@@ -71,6 +72,7 @@
mId = builder.mId;
mName = builder.mName;
+ mOwnerPackageName = builder.mOwnerPackageName;
mClientPackageName = builder.mClientPackageName;
mProviderId = builder.mProviderId;
@@ -96,6 +98,7 @@
mId = ensureString(src.readString());
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+ mOwnerPackageName = src.readString();
mClientPackageName = ensureString(src.readString());
mProviderId = src.readString();
@@ -159,6 +162,15 @@
}
/**
+ * Gets the package name of the session owner.
+ * @hide
+ */
+ @Nullable
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
+ /**
* Gets the client package name of the session
*/
@NonNull
@@ -263,6 +275,7 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mId);
dest.writeCharSequence(mName);
+ dest.writeString(mOwnerPackageName);
dest.writeString(mClientPackageName);
dest.writeString(mProviderId);
dest.writeStringList(mSelectedRoutes);
@@ -288,6 +301,7 @@
RoutingSessionInfo other = (RoutingSessionInfo) obj;
return Objects.equals(mId, other.mId)
&& Objects.equals(mName, other.mName)
+ && Objects.equals(mOwnerPackageName, other.mOwnerPackageName)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
&& Objects.equals(mProviderId, other.mProviderId)
&& Objects.equals(mSelectedRoutes, other.mSelectedRoutes)
@@ -301,7 +315,7 @@
@Override
public int hashCode() {
- return Objects.hash(mId, mName, mClientPackageName, mProviderId,
+ return Objects.hash(mId, mName, mOwnerPackageName, mClientPackageName, mProviderId,
mSelectedRoutes, mSelectableRoutes, mDeselectableRoutes, mTransferableRoutes,
mVolumeMax, mVolumeHandling, mVolume);
}
@@ -356,6 +370,7 @@
// TODO: Reorder these (important ones first)
final String mId;
CharSequence mName;
+ String mOwnerPackageName;
String mClientPackageName;
String mProviderId;
final List<String> mSelectedRoutes;
@@ -440,6 +455,17 @@
}
/**
+ * Sets the package name of the session owner. It is expected to be called by the system.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setOwnerPackageName(@Nullable String packageName) {
+ mOwnerPackageName = packageName;
+ return this;
+ }
+
+ /**
* Sets the client package name of the session.
*
* @hide
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f058a02..e701055 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1805,7 +1805,7 @@
String tvInputSessionId, int priorityHint,
Executor executor, final HardwareCallback callback) {
try {
- return new Hardware(
+ ITvInputHardware hardware =
mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@Override
public void onReleased() {
@@ -1826,7 +1826,11 @@
Binder.restoreCallingIdentity(identity);
}
}
- }, info, mUserId, tvInputSessionId, priorityHint));
+ }, info, mUserId, tvInputSessionId, priorityHint);
+ if (hardware == null) {
+ return null;
+ }
+ return new Hardware(hardware);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
index 598ff8f..28f1ac9 100644
--- a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
+++ b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
@@ -17,6 +17,7 @@
package android.media.tv.tunerresourcemanager;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -81,7 +82,7 @@
* OEM. The id of the useCaseVendor should be passed through this parameter. Any
* undefined use case would cause IllegalArgumentException.
*/
- public ResourceClientProfile(@NonNull String tvInputSessionId,
+ public ResourceClientProfile(@Nullable String tvInputSessionId,
int useCase) {
mTvInputSessionId = tvInputSessionId;
mUseCase = useCase;
@@ -92,7 +93,7 @@
*
* @return the value of the tv input session id.
*/
- @NonNull
+ @Nullable
public String getTvInputSessionId() {
return mTvInputSessionId;
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index aba74e5..ed56b43 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -165,6 +165,7 @@
MtpConstants.PROPERTY_TRACK,
MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
MtpConstants.PROPERTY_DURATION,
+ MtpConstants.PROPERTY_GENRE,
MtpConstants.PROPERTY_COMPOSER,
MtpConstants.PROPERTY_AUDIO_WAVE_CODEC,
MtpConstants.PROPERTY_BITRATE_TYPE,
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index 5bb0c1b..aff2e1b4 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -122,15 +122,21 @@
type = MtpConstants.TYPE_STR;
break;
case MtpConstants.PROPERTY_ARTIST:
+ column = Audio.AudioColumns.ARTIST;
type = MtpConstants.TYPE_STR;
break;
case MtpConstants.PROPERTY_ALBUM_NAME:
+ column = Audio.AudioColumns.ALBUM;
type = MtpConstants.TYPE_STR;
break;
case MtpConstants.PROPERTY_ALBUM_ARTIST:
column = Audio.AudioColumns.ALBUM_ARTIST;
type = MtpConstants.TYPE_STR;
break;
+ case MtpConstants.PROPERTY_GENRE:
+ column = Audio.AudioColumns.GENRE;
+ type = MtpConstants.TYPE_STR;
+ break;
case MtpConstants.PROPERTY_COMPOSER:
column = Audio.AudioColumns.COMPOSER;
type = MtpConstants.TYPE_STR;
diff --git a/media/packages/BluetoothMidiService/tests/unit/src/com/android/bluetoothmidiservice/BluetoothMidiEncoderTest.java b/media/packages/BluetoothMidiService/tests/unit/src/com/android/bluetoothmidiservice/BluetoothMidiEncoderTest.java
index a169c0d..d48b10a 100644
--- a/media/packages/BluetoothMidiService/tests/unit/src/com/android/bluetoothmidiservice/BluetoothMidiEncoderTest.java
+++ b/media/packages/BluetoothMidiService/tests/unit/src/com/android/bluetoothmidiservice/BluetoothMidiEncoderTest.java
@@ -74,10 +74,17 @@
}
void compareWithExpected(final byte[][] expected) {
+ // The data travels through the encoder in another thread
+ // so there is the potential for a race condition.
+ try {
+ Thread.sleep(50);
+ writeComplete(); // flushes any pending data
+ } catch (InterruptedException e) {
+ }
byte[][] actualRows = mReceiver.getBuffers();
- assertEquals(expected.length, actualRows.length);
+ int minRows = Math.min(expected.length, actualRows.length);
// Compare the gathered rows with the expected rows.
- for (int i = 0; i < expected.length; i++) {
+ for (int i = 0; i < minRows; i++) {
byte[] expectedRow = expected[i];
Log.d(TAG, "expectedRow = "
+ MidiFramer.formatMidiData(expectedRow, 0, expectedRow.length));
@@ -89,6 +96,7 @@
assertEquals(expectedRow[k], actualRow[k]);
}
}
+ assertEquals(expected.length, actualRows.length);
}
void writeComplete() {
@@ -115,8 +123,11 @@
(byte) 0x80, // high bit of header must be set
(byte) 0x80, // high bit of timestamp
(byte) 0x90, 0x40, 0x64,
- // encoder converts to running status
- 0x47, 0x72
+ },
+ {
+ (byte) 0x80, // high bit of header must be set
+ (byte) 0x80, // high bit of timestamp
+ (byte) 0x90, 0x47, 0x72
}};
EncoderChecker checker = new EncoderChecker();
checker.send(new byte[] {(byte) 0x90, 0x40, 0x64, (byte) 0x90, 0x47, 0x72});
@@ -129,7 +140,9 @@
(byte) 0x80, // high bit of header must be set
(byte) 0x80, // high bit of timestamp
(byte) 0x93, 0x40, 0x60,
- // two channels so no running status
+ },
+ {
+ (byte) 0x80, // high bit of header must be set
(byte) 0x80, // high bit of timestamp
(byte) 0x95, 0x47, 0x64
}};
@@ -166,9 +179,6 @@
checker.send(new byte[] {(byte) 0x90, 0x40, 0x64}, timestamp);
timestamp += 2 * NANOS_PER_MSEC;
checker.send(new byte[] {(byte) 0x90, 0x47, 0x72}, timestamp);
- // Tell the encoder that the first packet has been written to the
- // hardware. So it can flush the two pending notes.
- checker.writeComplete();
checker.compareWithExpected(encoded);
}
@@ -207,9 +217,6 @@
checker.send(new byte[] {(byte) 0xF0, 0x7D, // experimental SysEx
0x01, 0x02});
checker.send(new byte[] {0x03, 0x04, 0x05, (byte) 0xF7});
- // Tell the encoder that the first packet has been written to the
- // hardware. So it can flush the remaining data.
- checker.writeComplete();
checker.compareWithExpected(encoded);
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 6a1e965..eee797a 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -26,6 +26,7 @@
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID1;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
@@ -68,6 +69,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -566,6 +568,41 @@
assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
+ /**
+ * Tests if getSelectableRoutes and getDeselectableRoutes filter routes based on
+ * selected routes
+ */
+ @Test
+ public void testGetSelectableRoutes_notReturnsSelectedRoutes() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ addRouterCallback(new RouteCallback() {});
+
+ CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ assertNotNull(newSessionInfo);
+ List<String> selectedRoutes = mManager.getSelectedRoutes(newSessionInfo).stream()
+ .map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+ for (MediaRoute2Info selectableRoute :
+ mManager.getSelectableRoutes(newSessionInfo)) {
+ assertFalse(selectedRoutes.contains(selectableRoute.getId()));
+ }
+ for (MediaRoute2Info deselectableRoute :
+ mManager.getDeselectableRoutes(newSessionInfo)) {
+ assertTrue(selectedRoutes.contains(deselectableRoute.getId()));
+ }
+ onSessionCreatedLatch.countDown();
+ }
+ });
+
+ mManager.selectRoute(mPackageName, routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
+ assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
throws Exception {
CountDownLatch addedLatch = new CountDownLatch(1);
diff --git a/packages/CarSystemUI/res/layout/super_notification_shade.xml b/packages/CarSystemUI/res/layout/super_notification_shade.xml
index e36d8ca..db71c91 100644
--- a/packages/CarSystemUI/res/layout/super_notification_shade.xml
+++ b/packages/CarSystemUI/res/layout/super_notification_shade.xml
@@ -44,14 +44,6 @@
</com.android.systemui.statusbar.BackDropView>
<com.android.systemui.statusbar.ScrimView
- android:id="@+id/scrim_for_bubble"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:importantForAccessibility="no"
- sysui:ignoreRightInset="true"
- />
-
- <com.android.systemui.statusbar.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index f066bf5..f8729c3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -20,15 +20,21 @@
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
import com.android.keyguard.KeyguardViewController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
import com.android.systemui.car.keyguard.CarKeyguardViewController;
import com.android.systemui.car.statusbar.CarStatusBar;
import com.android.systemui.car.statusbar.CarStatusBarKeyguardViewManager;
+import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController;
import com.android.systemui.car.volume.CarVolumeDialogComponent;
import com.android.systemui.dagger.SystemUIRootComponent;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.plugins.qs.QSFactory;
@@ -47,6 +53,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -111,10 +118,17 @@
abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager(
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
- @Binds
+ @Provides
@Singleton
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
+ static BatteryController provideBatteryController(Context context,
+ EnhancedEstimates enhancedEstimates, PowerManager powerManager,
+ BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler,
+ @Background Handler bgHandler) {
+ BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
+ broadcastDispatcher, mainHandler, bgHandler);
+ bC.init();
+ return bC;
+ }
@Binds
@Singleton
@@ -156,4 +170,8 @@
@Binds
abstract CarDeviceProvisionedController bindCarDeviceProvisionedController(
CarDeviceProvisionedControllerImpl deviceProvisionedController);
+
+ @Binds
+ abstract NotificationShadeWindowController bindNotificationShadeWindowController(
+ DummyNotificationShadeWindowController notificationShadeWindowController);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
index af8ddb6..236a6a4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
@@ -49,6 +49,7 @@
@Singleton
public class HvacController {
public static final String TAG = "HvacController";
+ private static final boolean DEBUG = true;
private final CarServiceProvider mCarServiceProvider;
private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
@@ -70,6 +71,9 @@
new HvacKey(propertyId, areaId));
if (temperatureViews != null && !temperatureViews.isEmpty()) {
float value = (float) val.getValue();
+ if (DEBUG) {
+ Log.d(TAG, "onChangeEvent: " + areaId + ":" + propertyId + ":" + value);
+ }
for (TemperatureView tempView : temperatureViews) {
tempView.setTemp(value);
}
@@ -145,6 +149,9 @@
private void initComponent(TemperatureView view) {
int id = view.getPropertyId();
int zone = view.getAreaId();
+ if (DEBUG) {
+ Log.d(TAG, "initComponent: " + zone + ":" + id);
+ }
try {
if (mHvacManager != null
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index baa6ac9..aee7643 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -171,6 +171,7 @@
mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true);
start();
+ getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ true);
reset(/* hideBouncerWhenShowing= */ false);
notifyKeyguardUpdateMonitor();
}
@@ -185,6 +186,7 @@
mBouncer.hide(/* destroyView= */ true);
mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true);
stop();
+ getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false);
mKeyguardStateController.notifyKeyguardDoneFading();
mViewMediatorCallback.keyguardGone();
notifyKeyguardUpdateMonitor();
@@ -213,7 +215,7 @@
@Override
public void onCancelClicked() {
- if (!mShowing) return;
+ if (mBouncer == null) return;
getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false);
getOverlayViewGlobalStateController().setWindowNeedsInput(/* needsInput= */ false);
@@ -229,19 +231,20 @@
@Override
public void dismissAndCollapse() {
- hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
+ if (!mBouncer.isSecure()) {
+ hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
+ }
}
@Override
public void startPreHideAnimation(Runnable finishRunnable) {
- if (!mShowing) return;
+ if (mBouncer == null) return;
mBouncer.startPreHideAnimation(finishRunnable);
}
@Override
public void setNeedsInput(boolean needsInput) {
- getOverlayViewGlobalStateController().setWindowFocusable(needsInput);
getOverlayViewGlobalStateController().setWindowNeedsInput(needsInput);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index fcc8c8c..893efdc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -44,8 +44,8 @@
import com.android.systemui.SystemUI;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedListener;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
@@ -58,6 +58,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -74,7 +75,7 @@
private final AutoHideController mAutoHideController;
private final ButtonSelectionStateListener mButtonSelectionStateListener;
private final Handler mMainHandler;
- private final Handler mBgHandler;
+ private final Executor mUiBgExecutor;
private final IStatusBarService mBarService;
private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
private final ButtonSelectionStateController mButtonSelectionStateController;
@@ -105,8 +106,10 @@
private boolean mDeviceIsSetUpForUser = true;
private boolean mIsUserSetupInProgress = false;
- private @BarTransitions.TransitionMode int mStatusBarMode;
- private @BarTransitions.TransitionMode int mNavigationBarMode;
+ @BarTransitions.TransitionMode
+ private int mStatusBarMode;
+ @BarTransitions.TransitionMode
+ private int mNavigationBarMode;
private boolean mStatusBarTransientShown;
private boolean mNavBarTransientShown;
@@ -120,7 +123,7 @@
AutoHideController autoHideController,
ButtonSelectionStateListener buttonSelectionStateListener,
@Main Handler mainHandler,
- @Background Handler bgHandler,
+ @UiBackground Executor uiBgExecutor,
IStatusBarService barService,
Lazy<KeyguardStateController> keyguardStateControllerLazy,
ButtonSelectionStateController buttonSelectionStateController,
@@ -136,7 +139,7 @@
mAutoHideController = autoHideController;
mButtonSelectionStateListener = buttonSelectionStateListener;
mMainHandler = mainHandler;
- mBgHandler = bgHandler;
+ mUiBgExecutor = uiBgExecutor;
mBarService = barService;
mKeyguardStateControllerLazy = keyguardStateControllerLazy;
mButtonSelectionStateController = buttonSelectionStateController;
@@ -232,7 +235,7 @@
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
mActivityManagerWrapper.registerTaskStackListener(mButtonSelectionStateListener);
- mBgHandler.post(() -> mCarNavigationBarController.connectToHvac());
+ mUiBgExecutor.execute(mCarNavigationBarController::connectToHvac);
// Lastly, call to the icon policy to install/update all the icons.
// Must be called on the main thread due to the use of observeForever() in
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index 9e194fb..288e5cf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -73,7 +73,7 @@
}
/**
- * Hides all navigation bars.
+ * Hides all system bars.
*/
public void hideBars() {
if (mTopView != null) {
@@ -85,7 +85,7 @@
}
/**
- * Shows all navigation bars.
+ * Shows all system bars.
*/
public void showBars() {
if (mTopView != null) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index 20fcca0..aeb1d39 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -29,41 +29,40 @@
import com.android.car.notification.R;
import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* A controller for SysUI's HUN display.
*/
@Singleton
public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotificationContainer {
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy;
+ private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private final ViewGroup mWindow;
private final FrameLayout mHeadsUpContentFrame;
- private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
-
@Inject
CarHeadsUpNotificationSystemContainer(Context context,
@Main Resources resources,
CarDeviceProvisionedController deviceProvisionedController,
WindowManager windowManager,
- Lazy<NotificationPanelViewController> notificationPanelViewControllerLazy) {
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
mCarDeviceProvisionedController = deviceProvisionedController;
- mNotificationPanelViewControllerLazy = notificationPanelViewControllerLazy;
+ mOverlayViewGlobalStateController = overlayViewGlobalStateController;
boolean showOnBottom = resources.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom);
+ // Use TYPE_STATUS_BAR_SUB_PANEL window type since we need to find a window that is above
+ // status bar but below navigation bar.
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
@@ -78,15 +77,11 @@
windowManager.addView(mWindow, lp);
mWindow.setVisibility(View.INVISIBLE);
mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content);
-
- mEnableHeadsUpNotificationWhenNotificationShadeOpen = resources.getBoolean(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
}
private void animateShow() {
- if ((mEnableHeadsUpNotificationWhenNotificationShadeOpen
- || !mNotificationPanelViewControllerLazy.get().isPanelExpanded())
- && mCarDeviceProvisionedController.isCurrentUserFullySetup()) {
+ if (mCarDeviceProvisionedController.isCurrentUserFullySetup()
+ && mOverlayViewGlobalStateController.shouldShowHUN()) {
mWindow.setVisibility(View.VISIBLE);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index cb9539a..1738091 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -73,6 +73,7 @@
private final CarNotificationListener mCarNotificationListener;
private final NotificationClickHandlerFactory mNotificationClickHandlerFactory;
private final StatusBarStateController mStatusBarStateController;
+ private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
private float mInitialBackgroundAlpha;
private float mBackgroundAlphaDiff;
@@ -144,6 +145,10 @@
+ " percentage");
}
mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha;
+
+ mEnableHeadsUpNotificationWhenNotificationShadeOpen = mResources.getBoolean(
+ com.android.car.notification.R.bool
+ .config_enableHeadsUpNotificationWhenNotificationShadeOpen);
}
@Override
@@ -151,6 +156,16 @@
reinflate();
}
+ @Override
+ protected boolean shouldShowNavigationBar() {
+ return true;
+ }
+
+ @Override
+ protected boolean shouldShowHUN() {
+ return mEnableHeadsUpNotificationWhenNotificationShadeOpen;
+ }
+
/** Reinflates the view. */
public void reinflate() {
ViewGroup container = (ViewGroup) getLayout();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
index 8f52638..41349b2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
@@ -26,8 +26,15 @@
import com.android.systemui.car.window.OverlayViewMediator;
import com.android.systemui.statusbar.policy.ConfigurationController;
-/** The view mediator which attaches the view controller to other elements of the system ui. */
-public abstract class NotificationPanelViewMediator implements OverlayViewMediator,
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * The view mediator which attaches the view controller to other elements of the system ui. Disables
+ * drag open behavior of the notification panel from any navigation bar.
+ */
+@Singleton
+public class NotificationPanelViewMediator implements OverlayViewMediator,
ConfigurationController.ConfigurationListener {
private final CarNavigationBarController mCarNavigationBarController;
@@ -36,6 +43,7 @@
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final ConfigurationController mConfigurationController;
+ @Inject
public NotificationPanelViewMediator(
CarNavigationBarController carNavigationBarController,
NotificationPanelViewController notificationPanelViewController,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DummyNotificationShadeWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DummyNotificationShadeWindowController.java
new file mode 100644
index 0000000..a423003
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DummyNotificationShadeWindowController.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.statusbar;
+
+import android.app.IActivityManager;
+import android.content.Context;
+import android.view.WindowManager;
+
+import com.android.systemui.car.window.SystemUIOverlayWindowController;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * A dummy implementation of {@link NotificationShadeWindowController}.
+ *
+ * TODO(b/155711562): This should be replaced with a longer term solution (i.e. separating
+ * {@link BiometricUnlockController} from the views it depends on).
+ */
+@Singleton
+public class DummyNotificationShadeWindowController extends NotificationShadeWindowController {
+ private final SystemUIOverlayWindowController mOverlayWindowController;
+
+ @Inject
+ public DummyNotificationShadeWindowController(Context context,
+ WindowManager windowManager, IActivityManager activityManager,
+ DozeParameters dozeParameters,
+ StatusBarStateController statusBarStateController,
+ ConfigurationController configurationController,
+ KeyguardBypassController keyguardBypassController,
+ SysuiColorExtractor colorExtractor,
+ DumpManager dumpManager,
+ SystemUIOverlayWindowController overlayWindowController) {
+ super(context, windowManager, activityManager, dozeParameters, statusBarStateController,
+ configurationController, keyguardBypassController, colorExtractor, dumpManager);
+ mOverlayWindowController = overlayWindowController;
+ }
+
+ @Override
+ public void setForceDozeBrightness(boolean forceDozeBrightness) {
+ // No op.
+ }
+
+ @Override
+ public void setNotificationShadeFocusable(boolean focusable) {
+ // The overlay window is the car sysui equivalent of the notification shade.
+ mOverlayWindowController.setWindowFocusable(focusable);
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 0fe9856..45808a8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -375,10 +375,10 @@
}
if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().setWindowVisible(true);
+ getOverlayViewGlobalStateController().showView(/* panelViewController= */ this);
}
if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().setWindowVisible(false);
+ getOverlayViewGlobalStateController().hideView(/* panelViewController= */ this);
}
getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getOverlayViewGlobalStateController().setWindowFocusable(visible);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 87f2020..30e2657 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -54,7 +54,6 @@
mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide);
}
-
/**
* Inflate layout owned by controller.
*/
@@ -72,7 +71,7 @@
}
/**
- * Returns [@code true} if layout owned by controller has been inflated.
+ * Returns {@code true} if layout owned by controller has been inflated.
*/
public final boolean isInflated() {
return mLayout != null;
@@ -125,4 +124,18 @@
protected final OverlayViewGlobalStateController getOverlayViewGlobalStateController() {
return mOverlayViewGlobalStateController;
}
+
+ /**
+ * Returns {@code true} if heads up notifications should be displayed over this view.
+ */
+ protected boolean shouldShowHUN() {
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if navigation bar should be displayed over this view.
+ */
+ protected boolean shouldShowNavigationBar() {
+ return false;
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index 290505f..70260b0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -16,14 +16,17 @@
package com.android.systemui.car.window;
+import android.annotation.Nullable;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -39,11 +42,17 @@
*/
@Singleton
public class OverlayViewGlobalStateController {
+ private static final boolean DEBUG = false;
private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName();
+ private static final int UNKNOWN_Z_ORDER = -1;
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
private final CarNavigationBarController mCarNavigationBarController;
@VisibleForTesting
- Set<String> mShownSet;
+ Map<OverlayViewController, Integer> mZOrderMap;
+ @VisibleForTesting
+ SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
+ @VisibleForTesting
+ OverlayViewController mHighestZOrder;
@Inject
public OverlayViewGlobalStateController(
@@ -52,7 +61,8 @@
mSystemUIOverlayWindowController = systemUIOverlayWindowController;
mSystemUIOverlayWindowController.attach();
mCarNavigationBarController = carNavigationBarController;
- mShownSet = new HashSet<>();
+ mZOrderMap = new HashMap<>();
+ mZOrderVisibleSortedMap = new TreeMap<>();
}
/**
@@ -66,51 +76,127 @@
}
/**
- * Show content in Overlay Window.
+ * Show content in Overlay Window using {@link OverlayPanelViewController}.
+ *
+ * This calls {@link OverlayViewGlobalStateController#showView(OverlayViewController, Runnable)}
+ * where the runnable is nullified since the actual showing of the panel is handled by the
+ * controller itself.
*/
- public void showView(OverlayViewController viewController, Runnable show) {
- if (mShownSet.isEmpty()) {
- mCarNavigationBarController.hideBars();
- setWindowVisible(true);
- }
-
- inflateView(viewController);
-
- show.run();
- mShownSet.add(viewController.getClass().getName());
-
- Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+ public void showView(OverlayPanelViewController panelViewController) {
+ showView(panelViewController, /* show= */ null);
}
/**
- * Hide content in Overlay Window.
+ * Show content in Overlay Window using {@link OverlayViewController}.
*/
- public void hideView(OverlayViewController viewController, Runnable hide) {
+ public void showView(OverlayViewController viewController, @Nullable Runnable show) {
+ debugLog();
+ if (mZOrderVisibleSortedMap.isEmpty()) {
+ setWindowVisible(true);
+ }
+ if (!(viewController instanceof OverlayPanelViewController)) {
+ inflateView(viewController);
+ }
+
+ if (show != null) {
+ show.run();
+ }
+
+ updateInternalsWhenShowingView(viewController);
+ refreshNavigationBarVisibility();
+
+ Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+ debugLog();
+ }
+
+ private void updateInternalsWhenShowingView(OverlayViewController viewController) {
+ int zOrder;
+ if (mZOrderMap.containsKey(viewController)) {
+ zOrder = mZOrderMap.get(viewController);
+ } else {
+ zOrder = mSystemUIOverlayWindowController.getBaseLayout().indexOfChild(
+ viewController.getLayout());
+ mZOrderMap.put(viewController, zOrder);
+ }
+
+ mZOrderVisibleSortedMap.put(zOrder, viewController);
+
+ refreshHighestZOrderWhenShowingView(viewController);
+ }
+
+ private void refreshHighestZOrderWhenShowingView(OverlayViewController viewController) {
+ if (mZOrderMap.getOrDefault(mHighestZOrder, UNKNOWN_Z_ORDER) < mZOrderMap.get(
+ viewController)) {
+ mHighestZOrder = viewController;
+ }
+ }
+
+ /**
+ * Hide content in Overlay Window using {@link OverlayPanelViewController}.
+ *
+ * This calls {@link OverlayViewGlobalStateController#hideView(OverlayViewController, Runnable)}
+ * where the runnable is nullified since the actual hiding of the panel is handled by the
+ * controller itself.
+ */
+ public void hideView(OverlayPanelViewController panelViewController) {
+ hideView(panelViewController, /* hide= */ null);
+ }
+
+ /**
+ * Hide content in Overlay Window using {@link OverlayViewController}.
+ */
+ public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
+ debugLog();
if (!viewController.isInflated()) {
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+ viewController.getClass().getName());
return;
}
- if (!mShownSet.contains(viewController.getClass().getName())) {
- Log.d(TAG, "Content cannot be hidden since it isn't shown: "
+ if (!mZOrderMap.containsKey(viewController)) {
+ Log.d(TAG, "Content cannot be hidden since it has never been shown: "
+ + viewController.getClass().getName());
+ return;
+ }
+ if (!mZOrderVisibleSortedMap.containsKey(mZOrderMap.get(viewController))) {
+ Log.d(TAG, "Content cannot be hidden since it isn't currently shown: "
+ viewController.getClass().getName());
return;
}
- hide.run();
- mShownSet.remove(viewController.getClass().getName());
+ if (hide != null) {
+ hide.run();
+ }
- if (mShownSet.isEmpty()) {
- mCarNavigationBarController.showBars();
+ mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController));
+ refreshHighestZOrderWhenHidingView(viewController);
+ refreshNavigationBarVisibility();
+
+ if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(false);
}
Log.d(TAG, "Content hidden: " + viewController.getClass().getName());
+ debugLog();
}
- /** Sets the window visibility state. */
- public void setWindowVisible(boolean expanded) {
- mSystemUIOverlayWindowController.setWindowVisible(expanded);
+ private void refreshHighestZOrderWhenHidingView(OverlayViewController viewController) {
+ if (mZOrderVisibleSortedMap.isEmpty()) {
+ mHighestZOrder = null;
+ return;
+ }
+ if (!mHighestZOrder.equals(viewController)) {
+ return;
+ }
+
+ mHighestZOrder = mZOrderVisibleSortedMap.get(mZOrderVisibleSortedMap.lastKey());
+ }
+
+ private void refreshNavigationBarVisibility() {
+ if (mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowNavigationBar()) {
+ mCarNavigationBarController.showBars();
+ } else {
+ mCarNavigationBarController.hideBars();
+ }
}
/** Returns {@code true} is the window is visible. */
@@ -118,13 +204,14 @@
return mSystemUIOverlayWindowController.isWindowVisible();
}
- /** Sets the focusable flag of the sysui overlawy window. */
- public void setWindowFocusable(boolean focusable) {
- mSystemUIOverlayWindowController.setWindowFocusable(focusable);
+ private void setWindowVisible(boolean visible) {
+ mSystemUIOverlayWindowController.setWindowVisible(visible);
}
- /** Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
- * sysui overlay window */
+ /**
+ * Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
+ * sysui overlay window.
+ */
public void setWindowNeedsInput(boolean needsInput) {
mSystemUIOverlayWindowController.setWindowNeedsInput(needsInput);
}
@@ -134,10 +221,34 @@
return mSystemUIOverlayWindowController.isWindowFocusable();
}
+ /** Sets the focusable flag of the sysui overlawy window. */
+ public void setWindowFocusable(boolean focusable) {
+ mSystemUIOverlayWindowController.setWindowFocusable(focusable);
+ }
+
/** Inflates the view controlled by the given view controller. */
public void inflateView(OverlayViewController viewController) {
if (!viewController.isInflated()) {
viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout());
}
}
+
+ /**
+ * Return {@code true} if OverlayWindow is in a state where HUNs should be displayed above it.
+ */
+ public boolean shouldShowHUN() {
+ return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
+ }
+
+ private void debugLog() {
+ if (!DEBUG) {
+ return;
+ }
+
+ Log.d(TAG, "mHighestZOrder: " + mHighestZOrder);
+ Log.d(TAG, "mZOrderVisibleSortedMap.size(): " + mZOrderVisibleSortedMap.size());
+ Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
+ Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
+ Log.d(TAG, "mZOrderMap: " + mZOrderMap);
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
index e1918ce..484aa63 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
@@ -18,6 +18,7 @@
import com.android.systemui.car.keyguard.CarKeyguardViewMediator;
import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
+import com.android.systemui.car.notification.NotificationPanelViewMediator;
import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
@@ -32,6 +33,13 @@
@Module
public abstract class OverlayWindowModule {
+ /** Injects NotificationPanelViewMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(NotificationPanelViewMediator.class)
+ public abstract OverlayViewMediator bindNotificationPanelViewMediator(
+ NotificationPanelViewMediator notificationPanelViewMediator);
+
/** Injects TopNotificationPanelViewMediator. */
@Binds
@IntoMap
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
new file mode 100644
index 0000000..03fe0e4
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/transparent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_1"
+ android:inflatedId="@+id/overlay_view_controller_1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_2"
+ android:inflatedId="@+id/overlay_view_controller_2"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub_3"
+ android:inflatedId="@+id/overlay_view_controller_3"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index a2192af..1b4621f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -16,9 +16,10 @@
package com.android.systemui.car.keyguard;
-import static com.google.common.truth.Truth.assertThat;
-
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -29,7 +30,6 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import com.android.internal.widget.LockPatternUtils;
@@ -40,7 +40,6 @@
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.car.window.SystemUIOverlayWindowController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
@@ -51,6 +50,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -61,28 +61,20 @@
public class CarKeyguardViewControllerTest extends SysuiTestCase {
private TestableCarKeyguardViewController mCarKeyguardViewController;
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- private ViewGroup mBaseLayout;
@Mock
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+ @Mock
private KeyguardBouncer mBouncer;
@Mock
private CarNavigationBarController mCarNavigationBarController;
@Mock
- private SystemUIOverlayWindowController mSystemUIOverlayWindowController;
- @Mock
private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
- mCarNavigationBarController, mSystemUIOverlayWindowController);
- mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.sysui_overlay_window, /* root= */ null);
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
-
mCarKeyguardViewController = new TestableCarKeyguardViewController(
mContext,
Handler.getMain(),
@@ -98,6 +90,8 @@
mock(FalsingManager.class),
() -> mock(KeyguardBypassController.class)
);
+ mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.sysui_overlay_window, /* root= */ null));
}
@Test
@@ -113,8 +107,7 @@
when(mBouncer.isSecure()).thenReturn(true);
mCarKeyguardViewController.show(/* options= */ null);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.VISIBLE);
+ verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), any());
}
@Test
@@ -130,8 +123,17 @@
when(mBouncer.isSecure()).thenReturn(false);
mCarKeyguardViewController.show(/* options= */ null);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.GONE);
+ // Here we check for both showView and hideView since the current implementation of show
+ // with bouncer being not secure has the following method execution orders:
+ // 1) show -> start -> showView
+ // 2) show -> reset -> dismissAndCollapse -> hide -> stop -> hideView
+ // Hence, we want to make sure that showView is called before hideView and not in any
+ // other combination.
+ InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
+ inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
+ any());
+ inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
+ any());
}
@Test
@@ -156,8 +158,11 @@
mCarKeyguardViewController.show(/* options= */ null);
mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0);
- assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo(
- View.GONE);
+ InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
+ inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
+ any());
+ inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
+ any());
}
@Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index c555f64..77eecac 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -21,19 +21,24 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
+import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
+import android.util.ArrayMap;
import android.view.Display;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.internal.view.AppearanceRegion;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
@@ -42,6 +47,8 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -58,7 +65,6 @@
private CarNavigationBar mCarNavigationBar;
private TestableResources mTestableResources;
private Handler mHandler;
- private Handler mBackgroundHandler;
@Mock
private CarNavigationBarController mCarNavigationBarController;
@@ -81,16 +87,38 @@
@Mock
private StatusBarIconController mIconController;
+ private RegisterStatusBarResult mBarResult;
+ private FakeExecutor mUiBgExecutor;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableResources = mContext.getOrCreateTestableResources();
mHandler = Handler.getMain();
- mBackgroundHandler = Handler.createAsync(TestableLooper.get(this).getLooper());
+ mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ mBarResult = new RegisterStatusBarResult(
+ /* icons= */ new ArrayMap<>(),
+ /* disabledFlags1= */ 0,
+ /* appearance= */ 0,
+ /* appearanceRegions= */ new AppearanceRegion[]{},
+ /* imeWindowVis= */ 0,
+ /* imeBackDisposition= */ 0,
+ /* showImeSwitcher= */ false,
+ /* disabledFlags2= */ 0,
+ /* imeToken= */ null,
+ /* navbarColorMangedByIme= */ false,
+ /* appFullscreen= */ false,
+ /* appImmersive= */ false,
+ /* transientBarTypes= */ new int[]{});
+ try {
+ when(mBarService.registerStatusBar(any())).thenReturn(mBarResult);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
mCarNavigationBar = new CarNavigationBar(mContext, mTestableResources.getResources(),
mCarNavigationBarController, mWindowManager, mDeviceProvisionedController,
new CommandQueue(mContext), mAutoHideController, mButtonSelectionStateListener,
- mHandler, mBackgroundHandler, mBarService, () -> mKeyguardStateController,
+ mHandler, mUiBgExecutor, mBarService, () -> mKeyguardStateController,
mButtonSelectionStateController, () -> mIconPolicy, () -> mIconController);
}
@@ -108,7 +136,7 @@
verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture());
deviceProvisionedCallbackCaptor.getValue().onUserSwitched();
- waitForIdleSync(mBackgroundHandler);
+ waitForIdleSync(mHandler);
verify(mButtonSelectionStateListener).onTaskStackChanged();
}
@@ -128,7 +156,7 @@
verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture());
deviceProvisionedCallbackCaptor.getValue().onUserSwitched();
- waitForIdleSync(mBackgroundHandler);
+ waitForIdleSync(mHandler);
verify(mCarNavigationBarController).showAllKeyguardButtons(false);
}
@@ -147,12 +175,12 @@
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture());
deviceProvisionedCallbackCaptor.getValue().onUserSwitched();
- waitForIdleSync(mBackgroundHandler);
+ waitForIdleSync(mHandler);
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
when(mKeyguardStateController.isShowing()).thenReturn(false);
deviceProvisionedCallbackCaptor.getValue().onUserSetupChanged();
- waitForIdleSync(mBackgroundHandler);
+ waitForIdleSync(mHandler);
verify(mCarNavigationBarController).hideAllKeyguardButtons(true);
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
index 6ac72a6..ccaeb45 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
@@ -28,9 +28,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
import org.junit.Test;
@@ -42,12 +42,11 @@
@TestableLooper.RunWithLooper
@SmallTest
public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase {
- private CarHeadsUpNotificationSystemContainer mDefaultController;
- private CarHeadsUpNotificationSystemContainer mOverrideEnabledController;
+ private CarHeadsUpNotificationSystemContainer mCarHeadsUpNotificationSystemContainer;
@Mock
private CarDeviceProvisionedController mCarDeviceProvisionedController;
@Mock
- private NotificationPanelViewController mNotificationPanelViewController;
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
@Mock
private WindowManager mWindowManager;
@@ -58,76 +57,63 @@
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.initMocks(/* testClass= */this);
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(false);
- when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(false);
+ when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(true);
+ when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
TestableResources testableResources = mContext.getOrCreateTestableResources();
- testableResources.addOverride(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, false);
-
- mDefaultController = new CarHeadsUpNotificationSystemContainer(mContext,
+ mCarHeadsUpNotificationSystemContainer = new CarHeadsUpNotificationSystemContainer(mContext,
testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
- () -> mNotificationPanelViewController);
-
- testableResources.addOverride(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, true);
-
- mOverrideEnabledController = new CarHeadsUpNotificationSystemContainer(mContext,
- testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
- () -> mNotificationPanelViewController);
+ mOverlayViewGlobalStateController);
}
@Test
public void testDisplayNotification_firstNotification_isVisible() {
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isTrue();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
public void testRemoveNotification_lastNotification_isInvisible() {
- mDefaultController.displayNotification(mNotificationView);
- mDefaultController.removeNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
public void testRemoveNotification_nonLastNotification_isVisible() {
- mDefaultController.displayNotification(mNotificationView);
- mDefaultController.displayNotification(mNotificationView2);
- mDefaultController.removeNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isTrue();
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView2);
+ mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
- public void testDisplayNotification_userSetupInProgress_isInvisible() {
- when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(true);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_userFullySetupTrue_isInvisible() {
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
@Test
- public void testDisplayNotification_userSetupIncomplete_isInvisible() {
- when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_userFullySetupFalse_isInvisible() {
+ when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
- public void testDisplayNotification_notificationPanelExpanded_isInvisible() {
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
- mDefaultController.displayNotification(mNotificationView);
- assertThat(mDefaultController.isVisible()).isFalse();
+ public void testDisplayNotification_overlayWindowStateShouldShowHUNFalse_isInvisible() {
+ when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(false);
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
}
@Test
- public void testDisplayNotification_notificationPanelExpandedEnabledHUNWhenOpen_isVisible() {
- when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true);
- mOverrideEnabledController.displayNotification(mNotificationView);
- assertThat(mOverrideEnabledController.isVisible()).isTrue();
+ public void testDisplayNotification_overlayWindowStateShouldShowHUNTrue_isVisible() {
+ mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
+ assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 8d705a8..45a05ac 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -339,7 +339,7 @@
mOverlayPanelViewController.setPanelVisible(true);
- verify(mOverlayViewGlobalStateController).setWindowVisible(true);
+ verify(mOverlayViewGlobalStateController).showView(mOverlayPanelViewController);
}
@Test
@@ -349,7 +349,7 @@
mOverlayPanelViewController.setPanelVisible(true);
- verify(mOverlayViewGlobalStateController, never()).setWindowVisible(true);
+ verify(mOverlayViewGlobalStateController, never()).showView(mOverlayPanelViewController);
}
@Test
@@ -377,7 +377,7 @@
mOverlayPanelViewController.setPanelVisible(false);
- verify(mOverlayViewGlobalStateController).setWindowVisible(false);
+ verify(mOverlayViewGlobalStateController).hideView(mOverlayPanelViewController);
}
@Test
@@ -387,7 +387,7 @@
mOverlayPanelViewController.setPanelVisible(false);
- verify(mOverlayViewGlobalStateController, never()).setWindowVisible(false);
+ verify(mOverlayViewGlobalStateController, never()).hideView(mOverlayPanelViewController);
}
@Test
@@ -428,10 +428,6 @@
private static class TestOverlayPanelViewController extends OverlayPanelViewController {
- private boolean mShouldAnimateCollapsePanel;
- private boolean mShouldAnimateExpandPanel;
- private boolean mShouldAllowClosingScroll;
-
boolean mOnAnimateCollapsePanelCalled;
boolean mAnimateCollapsePanelCalled;
boolean mOnAnimateExpandPanelCalled;
@@ -440,6 +436,9 @@
boolean mOnExpandAnimationEndCalled;
boolean mOnOpenScrollStartEnd;
List<Integer> mOnScrollHeights;
+ private boolean mShouldAnimateCollapsePanel;
+ private boolean mShouldAnimateExpandPanel;
+ private boolean mShouldAllowClosingScroll;
TestOverlayPanelViewController(
Context context,
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index 25dd4f5..9e6e616 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -24,25 +24,33 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.ViewStub;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
+import com.android.systemui.tests.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
- private static final String MOCK_OVERLAY_VIEW_CONTROLLER_NAME = "OverlayViewController";
+ private static final int OVERLAY_VIEW_CONTROLLER_1_Z_ORDER = 0;
+ private static final int OVERLAY_VIEW_CONTROLLER_2_Z_ORDER = 1;
+ private static final int OVERLAY_PANEL_VIEW_CONTROLLER_Z_ORDER = 2;
private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private ViewGroup mBaseLayout;
@@ -54,7 +62,11 @@
@Mock
private OverlayViewMediator mOverlayViewMediator;
@Mock
- private OverlayViewController mOverlayViewController;
+ private OverlayViewController mOverlayViewController1;
+ @Mock
+ private OverlayViewController mOverlayViewController2;
+ @Mock
+ private OverlayPanelViewController mOverlayPanelViewController;
@Mock
private Runnable mRunnable;
@@ -62,14 +74,15 @@
public void setUp() {
MockitoAnnotations.initMocks(/* testClass= */ this);
+ mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.overlay_view_global_state_controller_test, /* root= */ null);
+
+ when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
+
mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
mCarNavigationBarController, mSystemUIOverlayWindowController);
verify(mSystemUIOverlayWindowController).attach();
-
- mBaseLayout = new FrameLayout(mContext);
-
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
}
@Test
@@ -87,182 +100,445 @@
}
@Test
- public void showView_nothingAlreadyShown_navigationBarsHidden() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ public void showView_nothingAlreadyShown_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mCarNavigationBarController).hideBars();
}
@Test
- public void showView_nothingAlreadyShown_windowIsExpanded() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ public void showView_nothingAlreadyShown_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_nothingAlreadyShown_windowIsSetVisible() {
+ setupOverlayViewController1();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mSystemUIOverlayWindowController).setWindowVisible(true);
}
@Test
- public void showView_somethingAlreadyShown_navigationBarsHidden() {
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void showView_nothingAlreadyShown_newHighestZOrder() {
+ setupOverlayViewController1();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
- verify(mCarNavigationBarController, never()).hideBars();
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController1);
}
@Test
- public void showView_somethingAlreadyShown_windowIsExpanded() {
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() {
+ setupOverlayViewController1();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
+ OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue();
+ }
+
+ @Test
+ public void showView_newHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void showView_newHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_newHighestZOrder_correctViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
+ .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
+ OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
+ }
+
+ @Test
+ public void showView_oldHighestZOrder() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void showView_oldHighestZOrder_correctViewsShown() {
+ setupOverlayViewController1();
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
+ .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
+ OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
+ }
+
+ @Test
+ public void showView_somethingAlreadyShown_windowVisibleNotCalled() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
verify(mSystemUIOverlayWindowController, never()).setWindowVisible(true);
}
@Test
public void showView_viewControllerNotInflated_inflateViewController() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ setupOverlayViewController2();
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
- verify(mOverlayViewController).inflate(mBaseLayout);
+ verify(mOverlayViewController2).inflate(mBaseLayout);
}
@Test
public void showView_viewControllerInflated_inflateViewControllerNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
+ setupOverlayViewController2();
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
- verify(mOverlayViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayViewController2, never()).inflate(mBaseLayout);
+ }
+
+ @Test
+ public void showView_panelViewController_inflateViewControllerNotCalled() {
+ setupOverlayPanelViewController();
+
+ mOverlayViewGlobalStateController.showView(mOverlayPanelViewController, mRunnable);
+
+ verify(mOverlayPanelViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayPanelViewController, never()).isInflated();
}
@Test
public void showView_showRunnableCalled() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+ setupOverlayViewController1();
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mRunnable).run();
}
@Test
- public void showView_overlayViewControllerAddedToShownSet() {
- mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mShownSet.contains(
- mOverlayViewController.getClass().getName())).isTrue();
- }
-
- @Test
public void hideView_viewControllerNotInflated_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_nothingShown_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.clear();
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mZOrderMap.clear();
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_viewControllerNotShown_hideRunnableNotCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mRunnable, never()).run();
}
@Test
public void hideView_viewControllerShown_hideRunnableCalled() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mRunnable).run();
}
@Test
- public void hideView_viewControllerOnlyShown_nothingShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ public void hideView_viewControllerOnlyShown_noHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
- assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue();
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isNull();
}
@Test
- public void hideView_viewControllerNotOnlyShown_navigationBarNotShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ public void hideView_viewControllerOnlyShown_nothingShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
- verify(mCarNavigationBarController, never()).showBars();
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void hideView_viewControllerOnlyShown_viewControllerNotShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
+ OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isFalse();
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_twoViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController1);
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_threeViewsShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ setupOverlayPanelViewController();
+ setOverlayViewControllerAsShowing(mOverlayPanelViewController);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayPanelViewController, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
+ mOverlayViewController2);
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
+ when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
}
@Test
public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
- mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ setupOverlayViewController2();
+ setOverlayViewControllerAsShowing(mOverlayViewController2);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
verify(mSystemUIOverlayWindowController, never()).setWindowVisible(false);
}
@Test
public void hideView_viewControllerOnlyShown_navigationBarShown() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mCarNavigationBarController).showBars();
}
@Test
public void hideView_viewControllerOnlyShown_windowCollapsed() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mShownSet.add(
- mOverlayViewController.getClass().getName());
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
- mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
verify(mSystemUIOverlayWindowController).setWindowVisible(false);
}
@Test
public void inflateView_notInflated_inflates() {
- when(mOverlayViewController.isInflated()).thenReturn(false);
+ when(mOverlayViewController2.isInflated()).thenReturn(false);
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController);
+ mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
- verify(mOverlayViewController).inflate(mBaseLayout);
+ verify(mOverlayViewController2).inflate(mBaseLayout);
}
@Test
public void inflateView_alreadyInflated_doesNotInflate() {
- when(mOverlayViewController.isInflated()).thenReturn(true);
+ when(mOverlayViewController2.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController);
+ mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
- verify(mOverlayViewController, never()).inflate(mBaseLayout);
+ verify(mOverlayViewController2, never()).inflate(mBaseLayout);
+ }
+
+ private void setupOverlayViewController1() {
+ setupOverlayViewController(mOverlayViewController1, R.id.overlay_view_controller_stub_1,
+ R.id.overlay_view_controller_1);
+ }
+
+ private void setupOverlayViewController2() {
+ setupOverlayViewController(mOverlayViewController2, R.id.overlay_view_controller_stub_2,
+ R.id.overlay_view_controller_2);
+ }
+
+ private void setupOverlayPanelViewController() {
+ setupOverlayViewController(mOverlayPanelViewController, R.id.overlay_view_controller_stub_3,
+ R.id.overlay_view_controller_3);
+ }
+
+ private void setupOverlayViewController(OverlayViewController overlayViewController,
+ int stubId, int inflatedId) {
+ ViewStub viewStub = mBaseLayout.findViewById(stubId);
+ View layout;
+ if (viewStub == null) {
+ layout = mBaseLayout.findViewById(inflatedId);
+ } else {
+ layout = viewStub.inflate();
+ }
+ when(overlayViewController.getLayout()).thenReturn(layout);
+ when(overlayViewController.isInflated()).thenReturn(true);
+ }
+
+ private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) {
+ mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null);
+ Mockito.reset(mCarNavigationBarController, mSystemUIOverlayWindowController);
+ when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
}
}
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 7f5c948..e153c91 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index 9dc2352..7fbeb3d 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 7f5c948..e153c91 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 388e939..f0eaf02 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index d41c672..43e3868 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -79,6 +79,7 @@
"com.android.apex.cts.shim.v2_unsigned_payload",
"com.android.apex.cts.shim.v3",
],
+ min_sdk_version: "24",
}
//##########################################################
@@ -152,4 +153,5 @@
"com.android.apex.cts.shim.v2_unsigned_payload",
"com.android.apex.cts.shim.v3",
],
+ min_sdk_version: "24",
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 83319cf..0c70e10 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -32,6 +32,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.DiskInfo;
+import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.DocumentsContract;
@@ -119,6 +120,14 @@
mUserManager = getContext().getSystemService(UserManager.class);
updateVolumes();
+
+ mStorageManager.registerListener(new StorageEventListener() {
+ @Override
+ public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+ updateVolumes();
+ }
+ });
+
return true;
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a95677d..5675c99 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -38,8 +38,6 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
@@ -526,18 +524,16 @@
case ContentResolver.SCHEME_FILE: {
File sourceFile = new File(packageUri.getPath());
- PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);
+ mPkgInfo = PackageUtil.getPackageInfo(this, sourceFile,
+ PackageManager.GET_PERMISSIONS);
// Check for parse errors
- if (parsed == null) {
+ if (mPkgInfo == null) {
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return false;
}
- mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index 0e89f56..d3a9f8f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -22,9 +22,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -53,12 +52,12 @@
/**
* Utility method to get package information for a given {@link File}
*/
- public static PackageParser.Package getPackageInfo(Context context, File sourceFile) {
- final PackageParser parser = new PackageParser();
- parser.setCallback(new PackageParser.CallbackImpl(context.getPackageManager()));
+ @Nullable
+ public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
try {
- return parser.parsePackage(sourceFile, 0);
- } catch (PackageParserException e) {
+ return context.getPackageManager().getPackageArchiveInfo(sourceFile.getAbsolutePath(),
+ flags);
+ } catch (Exception ignored) {
return null;
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
index e5f7613..06b1c16 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -22,11 +22,11 @@
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
@@ -49,6 +49,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -244,47 +245,50 @@
Log.e(TAG, "Could not create a temp file from FD for " + packageName);
return;
}
- PackageParser.Package pkg = PackageUtil.getPackageInfo(this, tempFile);
- if (pkg == null) {
+ PackageInfo pkgInfo = PackageUtil.getPackageInfo(this, tempFile,
+ PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS);
+ if (pkgInfo == null) {
Log.e(TAG, "Could not parse apk information for " + packageName);
return;
}
- if (!pkg.packageName.equals(packageName)) {
+ if (!pkgInfo.packageName.equals(packageName)) {
Log.e(TAG, "Wearable Package Name has to match what is provided for " +
packageName);
return;
}
- pkg.applicationInfo.sourceDir = tempFile.getPath();
- pkg.applicationInfo.publicSourceDir = tempFile.getPath();
+ ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ appInfo.sourceDir = tempFile.getPath();
+ appInfo.publicSourceDir = tempFile.getPath();
getLabelAndUpdateNotification(packageName,
- getString(R.string.installing_app, pkg.applicationInfo.loadLabel(pm)));
+ getString(R.string.installing_app, appInfo.loadLabel(pm)));
- List<String> wearablePerms = pkg.requestedPermissions;
+ List<String> wearablePerms = Arrays.asList(pkgInfo.requestedPermissions);
// Log if the installed pkg has a higher version number.
if (existingPkgInfo != null) {
- if (existingPkgInfo.getLongVersionCode() == pkg.getLongVersionCode()) {
+ long longVersionCode = pkgInfo.getLongVersionCode();
+ if (existingPkgInfo.getLongVersionCode() == longVersionCode) {
if (skipIfSameVersion) {
- Log.w(TAG, "Version number (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number (" + longVersionCode +
") of new app is equal to existing app for " + packageName +
"; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is equal to existing app for " + packageName);
}
- } else if (existingPkgInfo.getLongVersionCode() > pkg.getLongVersionCode()) {
+ } else if (existingPkgInfo.getLongVersionCode() > longVersionCode) {
if (skipIfLowerVersion) {
// Starting in Feldspar, we are not going to allow downgrades of any app.
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() +
") for " + packageName + "; not installing due to versionCheck");
return;
} else {
- Log.w(TAG, "Version number of new app (" + pkg.getLongVersionCode() +
+ Log.w(TAG, "Version number of new app (" + longVersionCode +
") is lower than existing app ( "
+ existingPkgInfo.getLongVersionCode() + ") for " + packageName);
}
@@ -309,14 +313,12 @@
// Check that the wearable has all the features.
boolean hasAllFeatures = true;
- if (pkg.reqFeatures != null) {
- for (FeatureInfo feature : pkg.reqFeatures) {
- if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
- (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
- Log.e(TAG, "Wearable does not have required feature: " + feature +
- " for " + packageName);
- hasAllFeatures = false;
- }
+ for (FeatureInfo feature : pkgInfo.reqFeatures) {
+ if (feature.name != null && !pm.hasSystemFeature(feature.name) &&
+ (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) {
+ Log.e(TAG, "Wearable does not have required feature: " + feature +
+ " for " + packageName);
+ hasAllFeatures = false;
}
}
@@ -328,8 +330,8 @@
// wearable package.
// If the app is targeting API level 23, we will also start a service in ClockworkHome
// which will ultimately prompt the user to accept/reject permissions.
- if (checkPerms && !checkPermissions(pkg, companionSdkVersion, companionDeviceVersion,
- permUri, wearablePerms, tempFile)) {
+ if (checkPerms && !checkPermissions(pkgInfo, companionSdkVersion,
+ companionDeviceVersion, permUri, wearablePerms, tempFile)) {
Log.w(TAG, "Wearable does not have enough permissions.");
return;
}
@@ -382,7 +384,7 @@
}
}
- private boolean checkPermissions(PackageParser.Package pkg, int companionSdkVersion,
+ private boolean checkPermissions(PackageInfo pkgInfo, int companionSdkVersion,
int companionDeviceVersion, Uri permUri, List<String> wearablePermissions,
File apkFile) {
// Assumption: We are running on Android O.
@@ -390,12 +392,12 @@
// app. If the Wear App is then not targeting M, there may be permissions that are not
// granted on the Phone app (by the user) right now and we cannot just grant it for the Wear
// app.
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+ if (pkgInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
// Install the app if Wear App is ready for the new perms model.
return true;
}
- if (!doesWearHaveUngrantedPerms(pkg.packageName, permUri, wearablePermissions)) {
+ if (!doesWearHaveUngrantedPerms(pkgInfo.packageName, permUri, wearablePermissions)) {
// All permissions requested by the watch are already granted on the phone, no need
// to do anything.
return true;
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 7e0ff81..1729027 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Wys opsies vir draadlose skermsertifisering"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag batteryverbruik en verbeter netwerk se werkverrigting"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hierdie skakelaar beïnvloed MAC-verewekansiginggedrag net vir klantmodus.\nWanneer hierdie modus geaktiveer is, kan enige netwerke waarvoor MAC-verewekansiging geaktiveer is, se MAC-adresse tydens die assosiasie weer verewigkansig word, na gelang van wanneer die klant laas van die netwerk ontkoppel het. Herverewekansiging vind nie plaas as die toestel binne 4 uur of korter herkoppel nie."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wanneer hierdie modus geaktiveer is, kan hierdie toestel se MAC-adres verander elke keer wanneer dit aan \'n netwerk koppel waarvoor MAC-verewekansiging geaktiveer is."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Beperk"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Onbeperk"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Loggerbuffer se groottes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Wys Program Reageer Nie-dialoog vir agtergrondprogramme"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Wys kennisgewingkanaalwaarskuwings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Wys waarskuwing op skerm wanneer \'n program \'n kennisgewing sonder \'n geldige kanaal plaas"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Dwing kortpaaie vir gesprekkennisgewings af"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kennisgewings moet deur \'n langleef-delingkortpad gerugsteun word om in gesprekafdeling te kan verskyn"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Dwing toelating op eksterne berging"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Maak dat enige program na eksterne berging geskryf kan word, ongeag manifeswaardes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Dwing aktiwiteite om verstelbaar te wees"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Toestelverstek"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Gedeaktiveer"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 391ceb7..fad7a82 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"የባትሪ መላሸቅን ይቀንሳል እንዲሁም የአውታረ መረብ አፈጻጸም ብቃትን ያሻሽላል"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ይህ ማብሪያ/ማጥፊያ የማክ ዘፈቀደ ማድረጊያ ባህሪ ላይ ተጽዕኖ የሚያሳርፈው ለደንበኛ ሁነታ ብቻ ነው።\nይህ ሁነታ ገቢር ሲደረግ የማክ ዘፈቀደ ማድረጊያ የነቃላቸው ማናቸውም አውታረ መረቦች ደንበኛው ከአውታረ መረቡ ጋር የተላቀቀበት መጨረሻ ጊዜ ላይ የሚወሰን ሆኖ በጉድኝቱ ጊዜ የማክ አድራሻዎቻቸው የዘፈቀደ ተደርጎ ሊሆን ይችላል። መሣሪያው በ4 ሰዓቶች ወይም ከዚያ ባነሰ ጊዜ ውስጥ ዳግም ከተገናኘ ዳግም የዘፈቀደ አይደረግም።"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ይህ ሁነታ ስራ ሲጀምር ይህ መሣሪያ የዘፈቀደ የማክ አድራሻ ስራ ከነቃለት አውታረ መረብ ጋር በተገናኘ እያንዳንዱ ጊዜ የመሣሪያው የማክ አድራሻ ሊቀየር ይችላል።"</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>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ለጀርባ መተግበሪያዎች የመተግበሪያ ምላሽ አይሰጥም መገናኛን አሳይ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"የማሳወቂያ ሰርጥ ማስጠንቀቂያዎችን አሳይ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"አንድ መተግበሪያ የሚሰራ ሰርጥ ሳይኖረው ማሳወቂያ ሲለጥፍ በማያ ገጽ-ላይ ማስጠንቀቂያን ያሳያል"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ለውይይት ማሳወቂያዎች አቋራጮች ተፈጻሚ ያድርጉ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"በውይይት ክፍል ውስጥ እንዲታይ በረዥም ጊዜ የሚቆይ የማጋራት አቋርጭ እንዲደገፉ ማሳወቂያዎችን ይጠይቁ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"በውጫዊ ላይ ሃይል ይፈቀዳል"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"የዝርዝር ሰነዶች እሴቶች ግምት ውስጥ ሳያስገባ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻው ለመጻፍ ብቁ ያደርጋል"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"የመሣሪያ ነባሪ"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ተሰናክሏል"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 51eae81..60f4c6b 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -179,7 +179,7 @@
<string name="tts_engine_settings_title" msgid="7849477533103566291">"إعدادات <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
<string name="tts_engine_settings_button" msgid="477155276199968948">"تشغيل إعدادات المحرك"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"المحرّك المفضّل"</string>
- <string name="tts_general_section_title" msgid="8919671529502364567">"عامة"</string>
+ <string name="tts_general_section_title" msgid="8919671529502364567">"إعدادات عامة"</string>
<string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"إعادة ضبط طبقة صوت الكلام"</string>
<string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"إعادة ضبط طبقة الصوت التي يتم قول النص بها على الإعداد التلقائي."</string>
<string-array name="tts_rate_entries">
@@ -235,7 +235,7 @@
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"يُرجى الاتصال بشبكة Wi-Fi."</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb، تصحيح الأخطاء، مطور برامج"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"اختصار تقرير الأخطاء"</string>
- <string name="bugreport_in_power_summary" msgid="1885529649381831775">"عرض زر في قائمة خيارات التشغيل لإعداد تقرير بالأخطاء"</string>
+ <string name="bugreport_in_power_summary" msgid="1885529649381831775">"عرض زر في قائمة زر التشغيل لإعداد تقرير بالأخطاء"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"البقاء في الوضع النشط"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"لا يتم مطلقًا دخول الشاشة في وضع السكون أثناء الشحن"</string>
<string name="bt_hci_snoop_log" msgid="7291287955649081448">"تفعيل سجلّ تطفل بواجهة وحدة تحكم المضيف في بلوتوث"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"لتقليل استنفاد البطارية وتحسين أداء الشبكة."</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"يؤثر مفتاح التبديل هذا في سلوك التوزيع العشوائي لعنوان MAC في وضع العميل فقط.\nعند تفعيل هذا الوضع، قد تتم عشوائيًا إعادة توزيع عناوين MAC أثناء الربط على أي شبكات تم تفعيل ميزة التوزيع العشوائي لعناوين MAC عليها، ويعتمد ذلك على آخر مرة تم فصل العميل فيها من الشبكة. لن تتم إعادة التوزيع العشوائي إذا تمت إعادة اتصال الجهاز خلال 4 ساعات أو أقل."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"عند تفعيل هذا الوضع، قد يتم تغيير عنوان MAC لهذا الجهاز في كل مرة تتصل فيها بشبكة تم تفعيل التوزيع العشوائي لعناوين MAC عليها."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"تفرض تكلفة استخدام"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"بدون قياس"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"عرض مربع الحوار \"التطبيق لا يستجيب\" مع تطبيقات الخلفية"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"عرض تحذيرات قناة الإشعار"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"عرض تحذير على الشاشة عندما ينشر تطبيق إشعارًا بدون قناة صالحة"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"فرض اختصارات لإشعارات المحادثات"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"يجب دعم الإشعارات باختصار مشاركة قديم لتظهر في قسم المحادثات."</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"السماح بإدراج التطبيقات في وحدة تخزين خارجية"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"تأهيل أي تطبيق بحيث تتم كتابته على وحدة تخزين خارجية، بغض النظر عن قيم البيان"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"فرض إمكانية تغيير حجم الأنشطة"</string>
@@ -555,4 +553,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ضيف"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 587151f..ad344c3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"বেটাৰীৰ খৰচ কমায় আৰু নেটৱৰ্কৰ কাৰ্যক্ষমতা বৃদ্ধি কৰে"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"এই ট\'গল কৰা কার্যই MAC যাদৃচ্ছিকীকৰণৰ আচৰণ কেৱল ক্লায়েণ্ট ম\'ডৰ বাবে প্ৰভাৱিত কৰে।\nএই ম\'ডটো সক্ৰিয় কৰাৰ সময়ত, ক্লায়েণ্টে শেষবাৰৰ বাবে নেটৱর্কটোৰ পৰা কেতিয়া সংযোগ বিচ্ছিন্ন কৰিছে তাৰ ভিত্তিত MAC যাদৃচ্ছিকীকৰণ সক্ষম কৰি থোৱা যিকোনো নেটৱর্কৰ সংযোজনৰ সময়ত MAC ঠিকনাসমূহৰ পুনৰ যাদৃচ্ছিকীকৰণ হ\'ব পাৰে। ডিভাইচটো ৪ ঘণ্টা অথবা তাতকৈ কম সময়ৰ ভিতৰত পুনৰ সংযুক্ত হ\'লে পুনৰ যাদৃচ্ছিকীকৰণ নহয়।"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"এই ম\'ডটো সক্ষম কৰিলে, এই ডিভাইচটোৱে MAC যাদৃচ্ছিকীকৰণ সক্ষম কৰি থোৱা কোনো নেটৱর্কত প্ৰতিবাৰ সংযোগ হোৱাৰ সময়ত ইয়াৰ MAC ঠিকনাটো সলনি হ\'ব পাৰে।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"নিৰিখ-নিৰ্দিষ্ট"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"নিৰিখ অনিৰ্দিষ্ট"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"লগাৰৰ বাফাৰৰ আকাৰ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"নেপথ্য এপসমূহৰ বাবে এপে সঁহাৰি দিয়া নাই ডায়ল\'গ প্ৰদৰ্শন কৰক"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"জাননী চ্চেনেলৰ সকীয়নিসমূহ দেখুৱাওক"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীণত সকীয়নি প্ৰদৰ্শন হয়"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"বার্তালাপৰ জাননীৰ বাবে শ্বৰ্টকাট কাৰ্যকৰী কৰক"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"বার্তালাপৰ শাখাত প্ৰদর্শিত হ\'বলৈ জাননী কোনো দীর্ঘস্থায়ী শ্বেয়াৰিং শ্বৰ্টকাটৰ সমৰ্থিত হ\'ব লাগে"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"বাহ্যিক সঞ্চয়াগাৰত এপক বলেৰে অনুমতি দিয়ক"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক সঞ্চয়াগাৰত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 738480f..5bf468f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya istifadəsini azaldır & şəbəkə performansını yaxşılaşdırır"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bu keçid yalnız müştəri rejimi üçün MAC randomizasiyasına təsir edir.\nBu rejim aktivləşdirildikdə müştərinin şəbəkədən sonuncu dəfə ayrıldığı vaxtdan asılı olaraq, əlaqələndirmə zamanı MAC randomizasiyası aktivləşdirilmiş istənilən şəbəkənin MAC ünvanı təkrar randomizasiya olunacaq. Cihaz 4 saat və ya daha qısa zaman sonra təkrar qoşularsa, təkrar randomizasiya baş vermir."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim deaktiv edildikdə, bu cihaz hər dəfə MAC randomizasiyası aktiv edilmiş şəbəkəyə qoşulanda onun MAC ünvanı dəyişə bilər."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Ödənişli"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Limitsiz"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger bufer ölçüləri"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Arxa fon tətbiqləri üçün Tətbiq Cavab Vermir dialoqunu göstərin"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Xəbərdarlıqları göstərin"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bildiriş paylaşıldıqda xəbərdarlıq göstərir"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Söhbət bildirişləri üçün qısayolları tətbiq edin"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Söhbət bölməsində görünmək üçün bildirişlərin uzunmüddətli paylaşım qısayolu ilə dəstəklənməsini tələb edin"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Tətbiqlərə xaricdən məcburi icazə"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
@@ -460,7 +458,7 @@
<string name="disabled" msgid="8017887509554714950">"Deaktiv"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"İcazə verilib"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"İcazə verilməyib"</string>
- <string name="install_other_apps" msgid="3232595082023199454">"Naməlum tətbiqlərin quraşdırılması"</string>
+ <string name="install_other_apps" msgid="3232595082023199454">"Tanınmayan tətbiqlərin quraşdırılması"</string>
<string name="home" msgid="973834627243661438">"Ayarların əsas səhifəsi"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 6187f93..85bb91c 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -143,11 +143,11 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Uklonjene aplikacije"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Uklonjene aplikacije i korisnici"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ažuriranja sistema"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB Internet povezivanje"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB privezivanje"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Prenosni hotspot"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth privezivanje"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Povezivanje sa internetom"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Povezivanje i prenosni hotspot"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Privezivanje"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Privezivanje i prenosni hotspot"</string>
<string name="managed_user_title" msgid="449081789742645723">"Sve radne aplikacije"</string>
<string name="user_guest" msgid="6939192779649870792">"Gost"</string>
<string name="unknown" msgid="3544487229740637809">"Nepoznato"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava učinak mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovaj prekidač utiče na ponašanje nasumičnog razvrstavanja MAC adresa samo za režim klijenta.\nKada se ovaj režim aktivira, za mreže na kojima je omogućeno nasumično razvrstavanje MAC adresa može da dođe do ponovnog nasumičnog razvrstavanja MAC adresa tokom povezivanja, u zavisnosti od toga kada se klijent pre toga isključio sa mreže. Do ponovnog nasumičnog razvrstavanja ne dolazi ako se uređaj ponovo poveže za 4 sata ili manje."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je ovaj režim omogućen, MAC adresa ovog uređaja može da se promeni svaki put kada se poveže sa mrežom na kojoj je omogućeno nasumično razvrstavanje MAC adresa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sa ograničenjem"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine bafera podataka u programu za evidentiranje"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaži dijalog Aplikacija ne reaguje za aplikacije u pozadini"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikazuj upozorenja zbog kanala za obaveštenja"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikazuje upozorenje na ekranu kada aplikacija postavi obaveštenje bez važećeg kanala"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primenjuj prečice za obaveštenja o konverzacijama"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Zahteva da obaveštenja imaju i dugoročnu prečicu za deljenje kako bi se pojavljivala u odeljku za konverzacije"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Prinudno dozvoli aplikacije u spoljnoj"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Prinudno omogući promenu veličine aktivnosti"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 6cca97d..95e1bdb 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"Невядома"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Карыстальнiк: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Усталяваны некаторыя стандартныя налады"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"Параметры па змаўчанні не ўсталяваныя"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"Стандартныя налады не зададзены"</string>
<string name="tts_settings" msgid="8130616705989351312">"Налады Text-to-speech"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Сінтэз маўлення"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Хуткасць маўлення"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Паказаць опцыі сертыфікацыі бесправаднога экрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зніжае расход зараду акумулятара і павышае прадукцыйнасць мабільных сетак"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Гэты пераключальнік уплывае на рандамізацыю MAC-адрасоў толькі ў кліенцкім рэжыме.\nКалі гэты рэжым актываваны, ва ўсіх сетках з уключанай рандамізацыяй MAC-адрасоў падчас прывязвання можа выконвацца паўторная рандамізацыя ў залежнасці ад таго, калі кліент адключаўся ад сеткі ў апошні раз. Паўторная рандамізацыя не выконваецца, калі прылада зноў падключаецца да сеткі менш чым праз 4 гадзіны."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Калі ўключаны гэты рэжым, MAC-адрас гэтай прылады можа змяняцца падчас кожнага падключэння да сеткі з актыўнай рандамізацыяй MAC-адрасоў."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Сетка з улікам трафіка"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Сетка без уліку трафіка"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Памеры буфера журнала"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Паведамляць аб тым, што праграма не адказвае"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Паказваць папярэджанні канала апавяшчэннаў"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Паказвае папярэджанне на экране, калі праграма публікуе апавяшчэнне без сапраўднага канала"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Выкарыстоўваць ярлыкі для апавяшчэнняў з размоў"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Каб апавяшчэнні паяўляліся ў раздзеле размоў, абавязкова дубліраваць іх з дапамогай ярлыкоў з працяглым паказам"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Прымусова дазволіць праграмы на вонкавым сховішчы"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Робіць любую праграму даступнай для запісу на вонкавае сховішча, незалежна ад значэнняў маніфеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Зрабіць вокны дзеянняў даступнымі для змены памеру"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Госць"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c128f3d..e426625 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показване на опциите за сертифициране на безжичния дисплей"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Намалява изразходването на батерията и подобрява ефективността на мрежата"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Този превключвател оказва влияние върху поведението при рандомизиране на MAC адреси само в режим на клиентска програма.\nКогато този режим е активиран, MAC адресът на всяка мрежа, за която функцията за рандомизиране е включена, може да бъде повторно рандомизиран по време на свързването в зависимост от това, кога последно клиентската програма е прекратила връзката си с мрежата. Не възниква повторно рандомизиране, ако устройството отново установи връзка до 4 часа."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Когато този режим е включен, MAC адресът на устройството може да се променя при всяко свързване с мрежа, за която е активирана функцията за рандомизиране на MAC адреса."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"С отчитане"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без отчитане"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Размери на регистрац. буфери"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Показване на диалоговия прозорец за грешки от типа ANR за приложенията на заден план"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Предупрежд. за канала за известия"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Показва се предупреждение, когато приложение публикува известие без валиден канал"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Налагане на преки пътища за извест. за разговори"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"За известията да се създава рез. копие чрез постоянен пряк път за споделяне, за да се показват в секцията с разговори"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Външно хран.: принуд. разрешаване на приложенията"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Всички приложения ще отговарят на условията да бъдат записвани във външното хранилище независимо от стойностите в манифеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Възможност за преоразмеряване на активностите"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index bdc9338..7bae6ee 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"অজানা"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ব্যবহারকারী: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"কিছু ডিফল্ট সেট করা রয়েছে"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"কোনো ডিফল্ট সেট করা নেই"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"কোনও ডিফল্ট সেট করা নেই"</string>
<string name="tts_settings" msgid="8130616705989351312">"পাঠ্য থেকে ভাষ্য আউটপুট সেটিংস"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"টেক্সট-টু-স্পিচ"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"কথা বলার হার"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ব্যাটারির খরচ কমায় এবং নেটওয়ার্কের পারফর্ম্যান্স উন্নত করে"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"এই টগলটি কেবল ক্লায়েন্ট মোডের জন্য ম্যাক র্যান্ডমাইজেশন আচরণকে প্রভাবিত করে।\nযখন এই মোডটি চালু করা হয়, তখন ক্লায়েন্টটি কখন নেটওয়ার্ক থেকে ডিসকানেক্ট হয়েছিল তার উপর নির্ভর করে কানেকশনটি সর্বশেষ কানেক্ট হওয়ার পরে MAC র্যান্ডম দ্বারা চালু করা যেকোনও MAC অ্যাড্রেস যেকোনও নেটওয়ার্কে আবার র্যান্ডমাইজেশন করা যেতে পারে। যদি ডিভাইসটি ৪ ঘন্টা বা তারও কম সময়ে আবার কানেক্ট করা হয় তবে এটি আর র্যান্ডমাইজেশন হবে না।"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"এই মোডটি চালু থাকার সময়, MAC র্যান্ডমাইজেশন চালু হওয়া এমন কোনও নেটওয়ার্কে কানেক্ট করার সময় এই ডিভাইসের MAC অ্যাড্রেস পরিবর্তিত হতে পারে।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"মিটার্ড"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"পরিমাপ করা নয়"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"লগার বাফারের আকারগুলি"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ব্যাকগ্রাউন্ডের অ্যাপগুলির জন্য \'অ্যাপ থেকে সাড়া পাওয়া যাচ্ছে না\' মেসেজ দেখান"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"বিজ্ঞপ্তির সতর্কতা দেখুন"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"অ্যাপ সঠিক চ্যানেল ছাড়া বিজ্ঞপ্তি দেখালে সতর্ক করে"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"কথোপকথনের বিজ্ঞপ্তির জন্য শর্টকাট ব্যবহার করুন"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"কথোপকথন বিভাগে দেখানোর জন্য বিজ্ঞপ্তিতে অনেকটা সময় ধরে চলে এমন শেয়ারিং শর্টকাট যেন থাকে"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"বহিরাগততে বলপূর্বক মঞ্জুরি"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 6f9188d..e965e5f 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećani nivo zapisnika za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava performanse mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovo aktiviranje/deaktiviranje utiče na ponašanje nasumičnog odabira MAC adrese isključivo za način rada klijenta.\nKada je taj način aktiviran, na svakoj mreži na kojoj je omogućen nasumični odabir MAC adrese može doći do ponovnog nasumičnog odabira MAC adrese za vrijeme povezivanja, u zavisnosti od toga kada je posljednji put prekinuta povezanost klijenta s mrežom. Do ponovnog nasumičnog odabira ne dolazi ako se uređaj ponovo poveže u roku od 4 sata ili ranije."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je omogućen ovaj način rada, MAC adresa ovog uređaja se može promijeniti svaki put kada se poveže na mrežu koja ima omogućen nasumični odabir MAC adresa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"S naplatom"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mreža bez naplate"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međumemorije zapisnika"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaz dijaloga \"Aplikacija ne reagira\" za aplikacije pokrenute u pozadini"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikaži upozorenja kanala obavještenja"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikaz upozorenja na ekranu kada aplikacija pošalje obavještenje bez važećeg kanala"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primijeni prečice za obavještenja o razgovorima"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Traži da obavještenja imaju dugotrajnu prečicu za dijeljenje radi prikaza u odjeljku za razgovore"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Nametni aplikacije na vanjskoj pohrani"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u vanjsku pohranu, bez obzira na prikazane vrijednosti"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Nametni aktivnostima mijenjanje veličina"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index da70d3b..2378d3a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra les opcions per a la certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Augmenta nivell de registre Wi‑Fi, mostra\'l per SSID RSSI al selector de Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Redueix el consum de bateria i millora el rendiment de la xarxa"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Aquest commutador afecta el comportament de l\'aleatorització d\'adreces MAC només en el mode client.\nQuan aquest mode està activat, és possible que les adreces MAC de les xarxes que tinguin activada l’aleatorització es tornin a ordenar de manera aleatòria durant l’associació, en funció de l\'última vegada que el client s\'ha desconnectat de la xarxa. Les adreces no es tornen a ordenar de manera aleatòria si el dispositiu es torna a connectar abans de 4 hores."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quan aquest mode està activat, és possible que l’adreça MAC d’aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la mem. intermèdia del registrador"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostra el quadre de diàleg L\'aplicació no respon per a aplicacions en segon pla"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostra avisos del canal de notificacions"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra un avís en pantalla quan una aplicació publica una notificació sense un canal vàlid"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Aplica dreceres per a notificacions de converses"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Requereix que les notificacions tinguin una drecera permanent de compartició perquè apareguin a la secció de converses"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Força permetre aplicacions de manera externa"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Força l\'ajust de la mida de les activitats"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 4d071b0..aa78612 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Snižuje vyčerpávání baterie a vylepšuje výkon sítě"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Tento přepínač má vliv pouze na chování randomizace adres MAC pro režim klienta.\nKdyž je tento režim aktivován, u sítí s povolenou randomizací adresa MAC mohou být během přidružování adresy MAC randomizovány znovu, podle toho, kdy se klient od sítě naposledy odpojil. Opětovná randomizace se neprovádí, pokud se zařízení připojí znovu do 4 hodin."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Když je tento režim aktivován, adresa MAC tohoto zařízení se může změnit pokaždé, když se zařízení připojí k síti s aktivovanou randomizací adres MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Měřená"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neměřená"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávací paměť protokol. nástroje"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Zobrazovat dialog „Aplikace neodpovídá“ pro aplikace na pozadí"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Zobrazovat upozornění ohledně kanálu oznámení"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Když aplikace odešle oznámení bez platného kanálu, na obrazovce se zobrazí upozornění"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"U oznámení konverzací vyžadovat zkratky"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"V sekci konverzace zobrazovat pouze oznámení podložená dlouhodobými sdílecími zkratkami"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Vynutit povolení aplikací na externím úložišti"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vynutit možnost změny velikosti aktivit"</string>
@@ -435,7 +433,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"Vydrží asi do <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">"Vydrží asi do <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"Do <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Baterie se může vybít do <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Baterie se může vybít kolem <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Zbývá více než <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index ba56d32..366bae3 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -211,10 +211,10 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Fejl"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs fejlretning"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Du kan se og bruge tilgængelige enheder ved at aktivere trådløs fejlretning"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Dan par med en enhed ved hjælp af en QR-kode"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Dan par med nye enheder ved hjælp af QR-kodescanneren"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Dan par med en enhed ved hjælp af en parringskode"</string>
- <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Dan par med nye enheder ved hjælp af den sekscifrede kode"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Par enhed ved hjælp af en QR-kode"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Par nye enheder ved hjælp af QR-kodescanneren"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Par enhed ved hjælp af en parringskode"</string>
+ <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Par nye enheder ved hjælp af den sekscifrede kode"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Parrede enheder"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Forbundet lige nu"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Enhedsoplysninger"</string>
@@ -222,16 +222,16 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Fingeraftryk for enhed: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Forbindelsen mislykkedes"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Sørg for, at <xliff:g id="DEVICE_NAME">%1$s</xliff:g> har forbindelse til det rigtige netværk."</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Dan par med enhed"</string>
+ <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Par med enhed"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Parringskode til Wi-Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Parringen mislykkedes"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Pardannelse mislykkedes"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for, at enheden er forbundet til det samme netværk."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Par en enhed via Wi-Fi ved at scanne en QR-kode"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Parrer enhed…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Enheden blev ikke parret. Det skyldes enten, at QR-koden var forkert, eller at enheden ikke er forbundet til det samme netværk."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR-kode"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Par en enhed via Wi-Fi ved at scanne en QR-kode"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Opret forbindelse til et Wi-Fi-netværk"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, fejlfinding, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Genvej til fejlrapportering"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis valgmuligheder for certificering af trådløs skærm"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reducerer batteriforbruget og forbedrer netværkets effektivitet"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Denne skift påvirker kun MAC-randomisering for klienttilstand.\nNår denne tilstand er aktiveret, kan netværk, der har Mac-randomisering aktiveret, få deres MAC-adresser randomiseret igen, når der oprettes forbindelse, afhængigt af hvornår klienten sidst afbrød forbindelse til netværket. Randomisering sker ikke igen, hvis enheden forbinder igen inden for højst 4 timer."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Når denne tilstand er aktiveret, skifter enhedens MAC-adresse muligvis, hver gang den opretter forbindelse til et netværk, hvor MAC-randomisering er aktiveret."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Forbrugsafregnet"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ikke forbrugsafregnet"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Størrelser for Logger-buffer"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Vis dialogboksen \"Appen svarer ikke\" for baggrundsapps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Vis advarsler om notifikationskanal"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viser en advarsel, når en app sender en notifikation uden en gyldig kanal"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kræv genveje til samtalenotifikationer"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kræv, at notifikationer bakkes op af en langvarig delingsgenvej, hvis de skal vises i samtalesektionen"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Gennemtving tilladelse til eksternt lager"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Gennemtving, at aktiviteter kan tilpasses"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 59c5b1d..74f59e2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -222,11 +222,11 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Fingerabdruck des Geräts: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Verbindung fehlgeschlagen"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Prüfe, ob <xliff:g id="DEVICE_NAME">%1$s</xliff:g> mit dem richtigen Netzwerk verbunden ist"</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Mit einem Gerät koppeln"</string>
+ <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Mit Gerät koppeln"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"WLAN-Kopplungscode"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Kopplung fehlgeschlagen"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Prüfe, ob das Gerät mit demselben Netzwerk verbunden ist."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Scanne einen QR-Code, um ein Gerät über WLAN zu koppeln"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Scanne einen QR-Code, um das Gerät über WLAN zu koppeln"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Gerät wird gekoppelt…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Das Gerät konnte nicht gekoppelt werden. Der QR-Code war nicht korrekt oder das Gerät ist nicht mit demselben Netzwerk verbunden."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-Adresse & Port"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"WLAN-Protokollierungsebene erhöhen, pro SSID RSSI in WiFi Picker anzeigen"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hiermit wird das Verhalten der MAC-Adressrandomisierung ausschließlich für den Clientmodus umgeschaltet.\nWenn dieser Modus aktiviert ist, werden bei allen Netzwerken, bei denen die MAC-Randomisierung aktiviert ist, die MAC-Adressen während der Verknüpfung abhängig davon, wann der Client zuletzt vom Netzwerk getrennt wurde, wieder randomisiert. Die erneute Randomisierung findet nicht statt, wenn die Verbindung des Geräts innerhalb von maximal 4 Stunden wiederhergestellt wird."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen randomisiert werden."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Kostenlos"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Bei Abstürzen von Hintergrund-Apps \"App reagiert nicht\"-Dialog anzeigen"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Benachrichtigungskanal- Warnungen anzeigen"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bei Benachrichtigungen ohne gültigen Kanal wird eine Warnung angezeigt"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Tastenkombination für Benachrichtigungen zur Unterhaltung erzwingen"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Benachrichtigungen müssen durch eine langlebige Tastenkombination zum Teilen unterstützt werden, um im Bereich der Unterhaltung zu erscheinen"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Sperrung des externen Speichers für alle Apps aufheben"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Jede App kann, ungeachtet der Manifestwerte, in den externen Speicher geschrieben werden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Aktivitätengröße darf immer angepasst werden"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 85defcb..c2502ef 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Περιορίζει την κατανάλωση της μπαταρίας και βελτιώνει την απόδοση του δικτύου"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Αυτός ο διακόπτης επηρεάζει τη συμπεριφορά της ρύθμισης τυχαίας σειράς διευθύνσεων MAC μόνο για τη λειτουργία εφαρμογής πελάτη.\nΌταν αυτή η λειτουργία είναι ενεργοποιημένη, σε όλα τα δίκτυα που είναι ενεργή η ρύθμιση τυχαίας σειράς διευθύνσεων MAC ενδέχεται να αλλάξει ξανά η τυχαία σειρά των διευθύνσεων MAC κατά τη συσχέτιση, ανάλογα με το πότε έγινε η τελευταία αποσύνδεση της εφαρμογής πελάτη από το δίκτυο. Αν η συσκευή επανασυνδεθεί μέσα σε 4 ώρες ή λιγότερες, τότε δεν θα αλλάξει η τυχαία σειρά."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Όταν ενεργοποιηθεί αυτή η λειτουργία, η διεύθυνση MAC αυτής της συσκευής μπορεί να αλλάζει κάθε φορά που συνδέεται σε ένα δίκτυο όπου έχει ενεργοποιηθεί η τυχαιοποίηση διευθύνσεων MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Μέτρηση με βάση τη χρήση"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Χωρίς μέτρηση με βάση τη χρήση"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Μέγεθος προσωρινής μνήμης για τη λειτουργία καταγραφής"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Εμφάνιση του παραθύρου \"Η εφαρμογή δεν αποκρίνεται\" για εφαρμογές παρασκηνίου"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Εμφάνιση προειδοπ. καναλιού ειδοπ."</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Εμφανίζει προειδοποίηση όταν μια εφαρμογή δημοσιεύει ειδοποίηση χωρίς έγκυρο κανάλι"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Επιβολή συντομεύσεων για ειδοποιήσεις συνομιλίας"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Να απαιτείται η υποστήριξη των ειδοπ. από μια συντόμευση κοινοποίησης μεγάλης διάρκειας για να εμφανίζονται στην ενότητα συνομιλίας"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Να επιτρέπονται υποχρεωτικά εφαρμογές σε εξωτ.συσ."</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό αποθηκευτικό χώρο, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 06be942..5fa9d45 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 06be942..5fa9d45 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 06be942..5fa9d45 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 06be942..5fa9d45 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index b0424e2..1cd2d84 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain & improves network performance"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomization behavior for client mode only.\nWhen this mode is activated, any networks that have MAC randomization enabled may have their MAC addresses re‑randomized during association, depending on when the client last disconnected from the network. Re‑randomization does not occur if the device reconnects in 4 hours or less."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"When this mode is enabled, this device’s MAC address may change each time it connects to a network that has MAC randomization enabled."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialog for background apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizable"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Device default"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 8744cb1..025cfc4 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -223,8 +223,8 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Error de conexión"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asegúrate de que <xliff:g id="DEVICE_NAME">%1$s</xliff:g> esté conectado a la red correcta."</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de sincroniz. de Wi‑Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Error de sincronización"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de vinculación de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Error de vinculación"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Asegúrate de que el dispositivo esté conectado a la misma red."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Escanea un código QR para vincular el dispositivo mediante Wi‑Fi"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Vinculando dispositivo…"</string>
@@ -284,8 +284,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Esta activación afecta el comportamiento de aleatorización de MAC para el modo de cliente solamente.\nCuando este modo está activado, todas las redes que tienen aleatorización de MAC habilitada pueden volver a establecer de manera aleatoria sus direcciones MAC durante la asociación, según cuándo el cliente se desconectó por última vez de la red. El proceso volver a establecer de manera aleatoria no se produce si el dispositivo se vuelve a conectar en 4 horas o menos."</string>
- <string name="wifi_metered_label" msgid="8737187690304098638">"Con uso medido"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
+ <string name="wifi_metered_label" msgid="8737187690304098638">"De uso medido"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string>
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Selecciona el tamaño del Logger por búfer"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar diálogo cuando las apps en segundo plano no responden"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Alertas de notificaciones"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Advertencia en pantalla cuando una app publica una notificación sin canal válido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Acc. dir. notif. de conv."</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Notif. requieren acc. dir. permanente de uso comp."</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permisos en almacenamiento externo"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cualquier app puede escribirse en un almacenamiento externo, sin importar los valores del manifiesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar actividades para que cambien de tamaño"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f1540e6..03b0495 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"Desconocido"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Usuario: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Se han establecido algunos valores predeterminados"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"No se han establecido valores predeterminados"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"No se han establecido opciones predeterminadas"</string>
<string name="tts_settings" msgid="8130616705989351312">"Ajustes de síntesis de voz"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Síntesis de voz"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de la voz"</string>
@@ -207,7 +207,7 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"Activar el modo de depuración cuando el dispositivo esté conectado por USB"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Revocar autorizaciones de depuración USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Depuración inalámbrica"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Activar el modo Depuración cuando tenga conexión Wi‑Fi"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Activa el modo de depuración cuando haya conexión Wi‑Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Error"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Depuración inalámbrica"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver y utilizar los dispositivos disponibles, activa la depuración inalámbrica"</string>
@@ -226,12 +226,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de sincronización de Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"No se ha podido vincular"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Comprueba que el dispositivo está conectado a la misma red."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Vincula un dispositivo a través de Wi‑Fi con un código QR"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Vincula un dispositivo mediante Wi‑Fi con un código QR"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Vinculando dispositivo…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"No se ha podido vincular el dispositivo. El código QR no era correcto o el dispositivo no estaba conectado a la misma red."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Dirección IP y puerto"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanea el código QR"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Vincula un dispositivo a través de Wi‑Fi escaneando un código QR"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Vincula un dispositivo mediante Wi‑Fi escaneando un código QR"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a una red Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depuración, desarrollo"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Atajo a informe de errores"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar el nivel de registro de Wi-Fi y mostrar por SSID RSSI en el selector Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de las redes"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Este interruptor solo afecta al comportamiento al aleatorizar direcciones MAC en el modo cliente.\nCuando este modo está activado, las direcciones MAC de las redes que tengan activada la aleatorización de la dirección MAC se pueden volver a aleatorizar durante la asociación. Esto depende de la última vez en la que el cliente se desconectó de la red. No se volverán a aleatorizar si transcurrieron 4 horas o menos desde la última conexión del dispositivo."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Medida"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"No medida"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños del búfer para registrar"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar el diálogo de que la aplicación no responde para aplicaciones en segundo plano"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ver advertencias del canal de notificaciones"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostrar una advertencia en pantalla cuando una aplicación publica una notificación sin un canal válido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Implementar atajos en notific. de conversaciones"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que las notificaciones tengan un atajo para compartir y que así aparezcan en la sección de conversaciones"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permitir aplicaciones de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hacer que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo independientemente de los valores definidos"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar el ajuste de tamaño de las actividades"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 206917e..4857b1e 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -212,7 +212,7 @@
<string name="adb_wireless_settings" msgid="2295017847215680229">"Juhtmevaba silumine"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Saadaolevate seadmete nägemiseks ja kasutamiseks lülitage sisse juhtmevaba silumine"</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Seadme sidumine QR-koodiga"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uute seadmete sidumine QR-koodi skanneriga"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uute seadmete sidumine QR-koodiskanneriga"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Seadme sidumine sidumiskoodiga"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Uute seadmete sidumine kuuekohalise koodiga"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Seotud seadmed"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Aeglustab aku tühjenemist ja parandab võrgu toimivust"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"See lüliti mõjutab MAC-aadressi juhuslikustamise käitumist ainult kliendirežiimis.\nSelle režiimi aktiveerimisel võidakse seostamise ajal MAC-aadressid uuesti juhuslikustada kõigi võrkude jaoks, millel on MAC-aadressi juhuslikustamine lubatud, olenevalt sellest, millal klient viimati ühenduse võrguga katkestas. Uuesti juhuslikustamist ei toimu juhul, kui seade loob uuesti ühenduse kuni 4 tunni jooksul."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kui see režiim on lubatud, võidakse selle seadme MAC-aadressi muuta iga kord, kui see ühendatakse võrguga, milles on juhusliku MAC-aadressi määramine lubatud."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mahupõhine"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mittemahupõhine"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logija puhvri suurused"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Kuva taustarakenduste puhul dialoog Rakendus ei reageeri"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kuva märguandekanali hoiatused"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Esitab ekraanil hoiatuse, kui rakendus postitab kehtiva kanalita märguande"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Otseteede jõustamine vestluste märguannete jaoks"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Nõutakse märguannete toetamist pikaajalise jagamise otseteega, et selle saaks vestluse jaotises kuvada"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Luba rakendused välises salvestusruumis"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lubab mis tahes rakendusi kirjutada välisesse salvestusruumi manifesti väärtustest olenemata"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Muuda tegevuste suurused muudetavaks"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index d2c2ae4..4d79747 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko."</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bezero modurako soilik MAC helbideak ausaz aukeratzeko eginbidearen portaerari eragiten dio etengailu honek.\nModu hau aktibatuta dagoenean, baliteke MAC helbideak ausaz aukeratzeko eginbidea aktibatuta daukaten sareen MAC helbideak berriro ausaz aukeratzea haiek lotu bitartean, bezeroa saretik deskonektatuta ematen duen denboraren arabera. Gailua lau ordu edo gutxiagoren buruan berriro konektatzen bada, ez da berriro MAC helbiderik ausaz aukeratuko."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Modu hau gaituta dagoenean, baliteke gailuaren MAC helbidea aldatzea MAC helbideak ausaz antolatzeko aukera gaituta daukan sare batera konektatzen den bakoitzean."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sare neurtua"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neurtu gabeko sarea"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Erregistroen buffer-tamainak"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Erakutsi aplikazioak ez erantzutearen (ANR) leihoa atzeko planoan dabiltzan aplikazioen kasuan"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Erakutsi jakinarazpenen kanalen abisuak"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bistaratu abisuak aplikazioek baliozko kanalik gabeko jakinarazpenak argitaratzean"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Erabili lasterbideak elkarrizketen jakinarazpenetan"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Eskatu jakinarazpenak partekatze-lasterbide iragankor batean oinarrituta egotea elkarrizketa-atalean agertzeko"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Behartu aplikazioak onartzea kanpoko memorian"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikazioek kanpoko memorian idatz dezakete, ezarritako balioak kontuan izan gabe"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Behartu jardueren tamaina doitu ahal izatea"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gailuaren balio lehenetsia"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index fba9ae5..d176114 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"ناشناس"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"کاربر: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"بعضی پیشفرضها تنظیم شدهاند"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"هیچ پیشفرضی تنظیم نشده است"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"پیشفرضی تنظیم نشده است"</string>
<string name="tts_settings" msgid="8130616705989351312">"تنظیمات متن به گفتار"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"خروجی تبدیل متن به گفتار"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"سرعت گفتار"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"تخلیه باتری راکاهش میدهد و عملکرد شبکه را بهبود میبخشد"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"فعال/غیرفعال کردن این تنظیم فقط درحالت کارخواه بر عملکرد تصادفیسازی MAC تأثیر میگذارد.\nوقتی این حالت فعال باشد، ممکن است در شبکههایی که تصادفیسازی MAC فعال است، نشانیهای MAC درطول ارتباط دوباره تصادفیسازی شوند، بسته به اینکه اتصال کارخواه آخرین بار چه زمانی از شبکه قطع شده باشد. اگر دستگاه ظرف ۴ ساعت یا کمتر دوباره متصل شود، تصادفیسازی مجدد انجام نمیشود."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"اگر این حالت فعال باشد، هر بار این دستگاه به شبکهای متصل شود که تصادفیسازی MAC در آن فعال است، ممکن است نشانی MAC آن تغییر کند."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"محدودشده"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"محدودنشده"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"اندازههای حافظه موقت ثبتکننده"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"نمایش گفتگوی \"برنامه پاسخ نمیدهد\" برای برنامههای پسزمینه"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"نمایش هشدارهای کانال اعلان"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"هنگامی که برنامهای بدون وجود کانالی معتبر، اعلانی پست میکند، هشدار روی صفحهای نمایش میدهد"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"اجرای میانبرها برای اعلانهای مکالمه"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"اعلانها باید با میانبر ماندگار همرسانی پشتیبانی شوند تا در بخش مکالمه نشان داده شوند"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"اجازه اجباری به برنامههای دستگاه ذخیره خارجی"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"بدون توجه به مقادیر آشکار، هر برنامهای را برای نوشتن در حافظه خارجی واجد شرایط میکند"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"اجبار فعالیتها به قابل تغییر اندازه بودن"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مهمان"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"پیشفرض دستگاه"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راهاندازی مجدد شود. اکنون راهاندازی مجدد کنید یا لغو کنید."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index c899d9c..af278cb 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -61,7 +61,7 @@
<string-array name="bt_hci_snoop_log_entries">
<item msgid="695678520785580527">"Ei käytössä"</item>
<item msgid="6336372935919715515">"Suodatus käytössä"</item>
- <item msgid="2779123106632690576">"Käytössä"</item>
+ <item msgid="2779123106632690576">"Päällä"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="8036025277512210160">"AVRCP 1.4 (oletus)"</item>
@@ -242,7 +242,7 @@
<item msgid="1212561935004167943">"Korosta testatut piirtokom. vihreällä"</item>
</string-array>
<string-array name="track_frame_time_entries">
- <item msgid="634406443901014984">"Pois käytöstä"</item>
+ <item msgid="634406443901014984">"Pois päältä"</item>
<item msgid="1288760936356000927">"Ruudulla palkkeina"</item>
<item msgid="5023908510820531131">"Kohteessa <xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 969180f..db5e957 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -24,7 +24,7 @@
<string name="wifi_security_none" msgid="7392696451280611452">"Ei mitään"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"Tallennettu"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"Yhteys katkaistu"</string>
- <string name="wifi_disabled_generic" msgid="2651916945380294607">"Pois käytöstä"</string>
+ <string name="wifi_disabled_generic" msgid="2651916945380294607">"Pois päältä"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP-kokoonpanovirhe"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Ei yhteyttä – verkko huonolaatuinen"</string>
<string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Wi-Fi-yhteysvirhe"</string>
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"Tuntematon"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Käyttäjä: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Joitakin oletuksia on asetettu"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"Oletuksia ei asetettu."</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"Oletuksia ei asetettu"</string>
<string name="tts_settings" msgid="8130616705989351312">"Tekstistä puheeksi -asetukset"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Tekstistä puheeksi -toisto"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Puheen nopeus"</string>
@@ -276,7 +276,7 @@
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Striimaus: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Yksityinen DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Valitse yksityinen DNS-tila"</string>
- <string name="private_dns_mode_off" msgid="7065962499349997041">"Pois käytöstä"</string>
+ <string name="private_dns_mode_off" msgid="7065962499349997041">"Pois päältä"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automaattinen"</string>
<string name="private_dns_mode_provider" msgid="3619040641762557028">"Yksityisen DNS-tarjoajan isäntänimi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Anna isäntänimi tai DNS-tarjoaja"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Näytä langattoman näytön sertifiointiin liittyvät asetukset."</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Vähentää virrankulutusta ja parantaa verkon toimintaa"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Tämä vaihto vaikuttaa MAC-satunnaistamistoimintaan vain asiakastilassa.\nTämän tilan ollessa aktivoituna niiden verkkojen, joissa MAC-satunnaistaminen on käytössä, MAC-osoitteet voidaan satunnaistaa uudelleen yhdistämisen aikana riippuen siitä, milloin asiakas katkaisi viimeksi yhteyden verkkoon. Uudelleensatunnaistamista ei tapahdu, jos laite yhdistetään uudelleen enintään neljän tunnin sisällä."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kun tämä tila on päällä, laitteen MAC-osoite voi muuttua aina, kun laite yhdistää verkkoon, jossa MAC-satunnaistaminen on käytössä."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Maksullinen"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Maksuton"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Lokipuskurien koot"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Näytä taustalla olevien sovellusten Sovellus ei vastaa ‑valintaikkunat."</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Näytä ilmoituskanavan varoitukset"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Näyttää varoituksen, kun sovellus julkaisee ilmoituksen ilman kelvollista kanavaa."</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Pakota pikanäppäimet keskusteluilmoituksissa"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vaadi ilmoitusten tukemista pitkäaikaisella jakopikanäppäimellä, jotta ne näkyvät keskusteluosiossa"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Salli aina ulkoinen tallennus"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Mahdollistaa sovelluksen tietojen tallentamisen ulkoiseen tallennustilaan luetteloarvoista riippumatta."</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
@@ -400,7 +398,7 @@
</string-array>
<string name="inactive_apps_title" msgid="5372523625297212320">"Valmiustilasovellukset"</string>
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Ei käytössä. Ota käyttöön koskettamalla."</string>
- <string name="inactive_app_active_summary" msgid="8047630990208722344">"Käytössä. Poista käytöstä koskettamalla."</string>
+ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiivinen. Vaihda koskettamalla."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Sovelluksen valmiusluokka: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
@@ -457,7 +455,7 @@
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Kytketty virtalähteeseen, lataaminen ei onnistu"</string>
<string name="battery_info_status_full" msgid="4443168946046847468">"Täynnä"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
- <string name="disabled" msgid="8017887509554714950">"Pois käytöstä"</string>
+ <string name="disabled" msgid="8017887509554714950">"Pois päältä"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Sallittu"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ei sallittu"</string>
<string name="install_other_apps" msgid="3232595082023199454">"Tuntemattomien sovellusten asentaminen"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 51f79ba..b8ff6598 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ce commutateur a un impact sur le comportement de sélection aléatoire des adresses MAC pour le mode client uniquement.\nLorsque ce mode est activé, l\'association pourrait forcer la réorganisation de manière aléatoire des adresses MAC pour les réseaux sur lesquels la sélection aléatoire des adresses MAC est activée, en fonction de la dernière fois que le client s\'est déconnecté du réseau. La réorganisation de manière aléatoire des adresses MAC ne se produit pas si l\'appareil se reconnecte d\'ici quatre heures ou moins."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecter à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher le message « L\'application ne répond plus » pour les applications en arrière-plan"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Affich. avertiss. canal notification"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afficher avertiss. à l\'écran quand une app présente une notific. sans canal valide"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Appliquer les raccourcis pour les notifications de conversation"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exiger le soutien des notifications par un raccourci de partage longue durée pour qu\'elles s\'affichent dans la section des conversations"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autor. d\'applis sur stockage externe"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forcer les activités à être redimensionnables"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Valeur par défaut de l\'appareil"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 5e6ee86..064e59f 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ce paramètre modifie uniquement le changement aléatoire de l\'adresse MAC en mode client.\nSi ce mode est activé, les réseaux pour lesquels le changement aléatoire d\'adresse MAC est activé peuvent faire l\'objet de nouveaux changements aléatoires d\'adresse lors des associations, en fonction du temps écoulé depuis la dernière fois que le client s\'est déconnecté du réseau. Aucun changement aléatoire d\'adresse n\'a lieu si un appareil se connecte à nouveau après un délai inférieur à quatre heures."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse e-mail MAC de cet appareil peut changer lors de chaque connexion à un réseau pour lequel le changement aléatoire d\'adresse MAC est activé."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher la boîte de dialogue \"L\'application ne répond plus\" pour les applications en arrière-plan"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Afficher les avertissements liés aux canaux de notification"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afficher un avertissement lorsqu\'une application publie une notification sans canal valide"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Utiliser des raccourcis pour les notifications des conversations"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exiger la sauvegarde des notifications via un raccourci de partage permanent pour qu\'elles s\'affichent dans la section des conversations"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autorisation d\'applis sur stockage externe"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Autoriser l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forcer le redimensionnement des activités"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index caa1f1b..8bb04f3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opcións para o certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta o nivel de rexistro da wifi, móstrao por SSID RSSI no selector de wifi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce o consumo de batería e mellora o rendemento da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Esta opción só lle afecta ao comportamento da selección aleatoria de enderezo MAC do modo de cliente.\nCando este modo está activado, os enderezos MAC das redes que teñan activada a selección automática de enderezo MAC pódense volver seleccionar aleatoriamente durante a asociación. Isto depende de cando se desconectase da rede cada cliente por última vez, xa que a selección aleatoria non se repite se transcorreron 4 horas ou menos desde a última conexión."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Cando este modo está activado, o enderezo MAC pode cambiar cada vez que se este dispositivo se conecta a unha rede que teña activada a orde aleatoria de enderezos MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sen tarifa plana"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Con tarifa plana"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamaño dos búfers do rexistrador"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Indica que unha aplicación en segundo plano non responde"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificacións"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra avisos cando unha aplicación publica notificacións sen unha canle válida"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atallos para notificacións de conversas"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require que as notificacións teñan un atallo de uso compartido permanente para aparecer na sección de conversas"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permiso de aplicacións de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite que calquera aplicación compatible se poida escribir nun almacenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forzar o axuste do tamaño das actividades"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 5bfe3a3..b88126b 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"પ્રોફાઇલ પસંદ કરો"</string>
<string name="category_personal" msgid="6236798763159385225">"વ્યક્તિગત"</string>
- <string name="category_work" msgid="4014193632325996115">"કાર્યાલય"</string>
+ <string name="category_work" msgid="4014193632325996115">"ઑફિસ"</string>
<string name="development_settings_title" msgid="140296922921597393">"વિકાસકર્તાનાં વિકલ્પો"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"વિકાસકર્તાનાં વિકલ્પો સક્ષમ કરો"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ઍપ્લિકેશન વિકાસ માટે વિકલ્પો સેટ કરો"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"બૅટરીનો ચાર્જ ઝડપથી ઓછો થવાનું ટાળે છે અને નેટવર્કની કાર્યક્ષમતામાં સુધારો કરે છે"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"આ ટોગલ માત્ર ક્લાયન્ટ મોડ માટે MAC રેન્ડમાઇઝ કરવાની વર્તણૂકને અસર કરે છે.\nઆ મોડ સક્રિય કરાય, ત્યારે MAC રેન્ડમાઇઝ કરવાનું ચાલુ કર્યું હોય તેવા કોઈપણ નેટવર્કના સંકલન દરમિયાન તેમના MAC ઍડ્રેસને રેન્ડમાઇઝ કરી શકાય છે અને તેનો આધાર ક્લાયન્ટ દ્વારા છેલ્લે ક્યારે નેટવર્કમાંથી ડિસ્કનેક્ટ કરાયું હતું તેના પર રહે છે. ડિવાઇસ 4 કલાક કે તેથી ઓછા સમયમાં ફરીથી કનેક્ટ થાય તો ફરી રેન્ડમાઇઝ કરાતું નથી."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"આ મોડ ચાલુ કરેલો હશે, ત્યારે MAC રેન્ડમાઇઝેશન ચાલુ કરેલું હોય તેવા નેટવર્ક સાથે આ ડિવાઇસ જોડાશે ત્યારે દર વખતે તેનું MAC ઍડ્રેસ બદલાય તેમ બની શકે છે."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"મીટર કરેલ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"મીટર ન કરેલ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"લોગર બફર કદ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"બૅકગ્રાઉન્ડ ઍપ માટે \"ઍપ પ્રતિસાદ આપતી નથી\" સંવાદ બતાવો"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"નોટિફિકેશન ચૅનલની ચેતવણી બતાવો"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ઍપ્લિકેશન માન્ય ચૅનલ વિના નોટિફિકેશન પોસ્ટ કરે તો સ્ક્રીન પર ચેતવણી દેખાય છે"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"વાતચીત સૂચનો માટે શૉર્ટકટ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"વાતચીત વિભાગમાં દેખાવા એક લાંબું ટકતા શેરિંગ શૉર્ટકટ દ્વારા ટેકો મેળવતા નોટિફિકેશન જરૂરી છે"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"બાહ્ય પર એપ્લિકેશનોને મંજૂરી આપવાની ફરજ પાડો"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ ઍપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
<string name="guest_nickname" msgid="6332276931583337261">"અતિથિ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 999e344..d8aa092 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिसप्ले सर्टिफ़िकेशन के विकल्प दिखाएं"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाई-फ़ाई लॉगिंग का स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बैटरी की खपत कम और नेटवर्क की परफ़ॉर्मेंस बेहतर होती है"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"इस टॉगल से सिर्फ़ क्लाइंट मोड में, वाई-फ़ाई नेटवर्क से जुड़ते समय मैक पते को बदलने की सुविधा पर असर पड़ता है.\nजब इस मोड को चालू किया जाता है, तब ऐसे किसी भी नेटवर्क का मैक पता फिर से बदला जा सकता है जिन पर मैक पते को बदलने की सुविधा चालू होती है. ऐसा तभी होता है, जब वे नेटवर्क जुड़े हों. यह इस पर भी निर्भर करता है कि क्लाइंट ने उसे नेटवर्क से कब डिसकनेक्ट किया था. अगर डिवाइस चार घंटे या उससे कम में, फिर से कनेक्ट होता है, तो मैक पते को दोबारा बदला नहीं जा सकता."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"जब यह मोड चालू होता है, तब नेटवर्क से कनेक्ट होने पर हर बार इस डिवाइस का MAC पता बदल सकता है. ऐसा तब होता है, जब डिवाइस किसी ऐसे नेटवर्क से जुड़ता है जिस पर MAC पते को बिना किसी तय नियम के बदलने की सुविधा चालू होती है."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"डेटा इस्तेमाल करने की सीमा तय की गई है"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"डेटा इस्तेमाल करने की सीमा तय नहीं की गई है"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफ़र आकार"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"बैकग्राउंड में चलने वाले ऐप्लिकेशन के लिए, यह ऐप्लिकेशन नहीं चल रहा मैसेज दिखाएं"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना चैनल चेतावनी दिखाएं"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ऐप्लिकेशन, मान्य चैनल के बिना सूचना पोस्ट करे तो स्क्रीन पर चेतावनी दिखाएं"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"सिर्फ़ वही सूचनाएं दिखाएं जो बातचीत सेक्शन में सही शॉर्टकट के साथ भी लिंक हैं"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ज़रूरी सूचनाओं के लिए ऐसा शेयरिंग शॉर्टकट होना चाहिए जो हमेशा (long-lived) मौजूद रहे, ताकि सूचनाओं को बातचीत वाले सेक्शन में देखा जा सके"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ऐप्लिकेशन को बाहरी मेमोरी पर ही चलाएं"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"इससे कोई भी ऐप्लिकेशन बाहरी मेमोरी में रखने लायक बन जाता है चाहे उसकी मेनिफ़ेस्ट वैल्यू कुछ भी हो"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"विंडो के हिसाब से गतिविधियों का आकार बदल दें"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 391d62c..548fc20 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -196,7 +196,7 @@
<string name="choose_profile" msgid="343803890897657450">"Odabir profila"</string>
<string name="category_personal" msgid="6236798763159385225">"Osobno"</string>
<string name="category_work" msgid="4014193632325996115">"Posao"</string>
- <string name="development_settings_title" msgid="140296922921597393">"Za razvojne programere"</string>
+ <string name="development_settings_title" msgid="140296922921597393">"Opcije za razvojne programere"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Omogući opcije za razvojne programere"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Postavljanje opcija za razvoj aplikacije"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Opcije razvojnih programera nisu dostupne za ovog korisnika"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava rad mreže"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovaj prekidač utječe na ponašanje nasumičnog odabira MAC-a samo za način korisnika.\nKad je aktiviran ovaj način rada, kod bilo koje mreže koja ima omogućen nasumični odabir MAC-a može doći do ponovnog nasumičnog odabira MAC adrese tijekom povezivanja, ovisno o tome kad se klijent posljednji put odspojio s mreže. Nema ponovnog nasumičnog odabira ako se uređaj ponovno spoji za manje od 4 sata."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kada je omogućen ovaj način, MAC adresa ovog uređaja može se promijeniti svaki put kad se uređaj poveže s mrežom na kojoj je omogućen nasumični odabir MAC-a."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"S ograničenim prometom"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja prometa"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međuspremnika zapisnika"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Dijalog o pozadinskim aplikacijama koje ne reagiraju"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikaži upozorenja kanala obavijesti"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikazuje upozorenje na zaslonu kada aplikacija objavi obavijest bez važećeg kanala"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primjena prečaca za obavijesti razgovora"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Obavijesti moraju imati dugotrajni prečac za dijeljenje da bi se prikazale u odjeljku razgovora"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Prisilno dopusti aplikacije u vanjskoj pohrani"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o vrijednostima manifesta"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Nametni mogućnost promjene veličine za aktivnosti"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 02a7b67..9e51cfd 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Csökkenti az akkumulátorhasználatot, és javítja a hálózat teljesítményét"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Kizárólag ügyfélmód esetében be- vagy kikapcsolja a MAC-címet randomizáló viselkedést.\nHa a mód aktív, az olyan hálózatokon, amelyeken engedélyezve van a MAC-címek randomizálása, a társítás során újra megtörténhet a randomizálás, attól függően, hogy az ügyfél mikor bontotta utoljára a kapcsolatot a hálózattal. Az ismételt randomizálás nem következik be, ha az eszköz négy órán belül újracsatlakozik."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ha ez a mód be van kapcsolva, akkor ennek az eszköznek a MAC-címe minden alkalommal módosulhat, amikor olyan hálózathoz csatlakozik, amelyen engedélyezve van a MAC-címek randomizálása."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Forgalomkorlátos"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Nem forgalomkorlátos"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Naplózási puffer mérete"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Az Alkalmazás nem válaszol ablak megjelenítése a háttérben futó alkalmazásoknál"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Értesítő csatorna figyelmeztetései"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Figyelmeztet, ha egy alkalmazás érvényes csatorna nélkül küld értesítést"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Gyorsparancsok kényszerítése beszélgetésértesítésekhez"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Megköveteli, hogy az értesítéseket hosszú életű megosztási gyorsparancs támogassa, hogy megjelenhessenek a beszélgetési szakaszban"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Külső tárhely alkalmazásainak engedélyezése"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lehetővé teszi bármely alkalmazás külső tárhelyre való írását a jegyzékértékektől függetlenül"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Tevékenységek átméretezésének kényszerítése"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 8b7679a..52e9175 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -278,13 +278,13 @@
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Ընտրեք մասնավոր DNS-ի ռեժիմը"</string>
<string name="private_dns_mode_off" msgid="7065962499349997041">"Անջատված է"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Ավտոմատ"</string>
- <string name="private_dns_mode_provider" msgid="3619040641762557028">"Մասնավոր DNS ծառայության մատակարարի խնամորդի անունը"</string>
+ <string name="private_dns_mode_provider" msgid="3619040641762557028">"Մասնավոր DNS մատակարարի սերվերը"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Մուտքագրեք DNS ծառայության մատակարարի խնամորդի անունը"</string>
<string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Չհաջողվեց միանալ"</string>
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ցույց տալ անլար էկրանների հավաստագրման ընտրանքները"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Նվազեցնում է մարտկոցի սպառումը և լավացնում ցանցի աշխատանքը"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Այս կարգավորումը միացնում է MAC հասցեների պատահական ընտրությունը միայն սպասառուի ռեժիմում։\nԵրբ այս ռեժիմն ակտիվացված է, բոլոր ցանցերը, որոնց համար միացված է MAC հասցեների պատահական ընտրությունը, կապակցման ժամանակ կարող են նորից պատահական MAC հասցե ընտրել՝ կախված այն բանից, թե երբ է սպասառուն վերջին անգամ անջատվել ցանցից։ Պատահական ընտրության կրկնությունը տեղի չի ունենում, եթե սարքը նորից է միանում ցանցին 4 ժամից պակաս ժամանակահատվածում։"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Երբ այս ռեժիմը միացված է, MAC հասցեն կարող է փոխվել ամեն անգամ, երբ սարքը միանա որևէ ցանցի, որում միացված է MAC հասցեների պատահական ընտրությունը։"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Վճարովի թրաֆիկ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Անսահմանափակ թրաֆիկ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Մատյանի բուֆերի չափերը"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Ցուցադրել «Հավելվածը չի արձագանքում» պատուհանը ֆոնային հավելվածների համար"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ցուցադրել ծանուցումների ալիքի զգուշացումները"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Էկրանին ցուցադրվում է զգուշացում, երբ որևէ հավելված փակցնում է ծանուցում առանց վավեր ալիքի"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Միացնել զրույցների ծանուցումների դյուրանցումները"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Պահանջել, որ ծանուցումները պահվեն երկարաժամկետ հասանելիության դյուրանցումով՝ զրույցների բաժնում հայտնվելու համար"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Թույլատրել պահումն արտաքին կրիչներում"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Թույլ է տալիս ցանկացած հավելված պահել արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Չափերի փոփոխում բազմապատուհան ռեժիմում"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Հյուր"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index fade9fc..561b7c4 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Memperlambat kehabisan baterai & meningkatkan performa jaringan"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Pengaktifan mode ini memengaruhi perilaku pengacakan MAC hanya untuk mode klien.\nSaat mode ini diaktifkan, jaringan yang mengaktifkan pengacakan MAC mungkin mengalami pengacakan ulang alamat MAC selama terhubung, bergantung pada kapan klien terakhir kali terputus dari jaringan. Pengacakan ulang tidak terjadi jika perangkat terhubung kembali dalam 4 jam atau kurang."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Saat mode ini diaktifkan, alamat MAC perangkat ini dapat berubah setiap kali terhubung ke jaringan yang mengaktifkan pengacakan MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Berbayar"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak berbayar"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Ukuran buffer pencatat log"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Tampilkan dialog Aplikasi Tidak Merespons untuk aplikasi yang berjalan di background"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Tampilkan peringatan saluran notifikasi"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Menampilkan peringatan di layar saat aplikasi memposting notifikasi tanpa channel yang valid"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Terapkan pintasan untuk notifikasi percakapan"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Mengharuskan notifikasi didukung oleh pintasan berbagi yang berdurasi panjang untuk muncul di bagian percakapan"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Paksa izinkan aplikasi di eksternal"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksternal, terlepas dari nilai manifes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktivitas agar ukurannya dapat diubah"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 543403a..e99faaf 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Dregur úr rafhlöðunotkun og eykur netafköst"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Þessi rofi hefur eingöngu áhrif á slembival MAC-vistfanga fyrir biðlarastillingu.\nÞegar þessi stilling er virk geta öll netkerfi sem eru með slembival MAC-vistfanga virkt látið slembiraða MAC-vistföngum aftur við tengingu, allt eftir því hvenær biðlarinn aftengdist netinu síðast. Endurslembiröðun á sér ekki stað ef tækið tengist aftur innan fjögurra klukkustunda."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Þegar kveikt er á þessari stillingu gæti MAC-vistfang þessa tækis breyst í hvert sinn sem það tengist neti sem er með kveikt á slembivali MAC-vistfanga."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mæld notkun"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Notkun ekki mæld"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Annálsritastærðir biðminna"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Sýna „Forrit svarar ekki“ fyrir bakgrunnsforrit"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Sýna viðvaranir tilkynningarásar"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Birtir viðvörun á skjánum þegar forrit birtir tilkynningu án gildrar rásar"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Þvinga flýtileiðir fyrir tilkynningar um samtöl"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Krefjast þess að flýtileiðir séu studdar af langvarandi deilingarflýtileið fyrir birtingu í samtalshluta"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Þvinga fram leyfi forrita í ytri geymslu"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gerir öll forrit skrifanleg í ytra geymslurými, óháð gildum í upplýsingaskrá"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Þvinga breytanlega stærð virkni"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index dd597d0..ece0ba4 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -207,11 +207,11 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"Modalità debug quando è connesso tramite USB"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Revoca autorizzazioni debug USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Debug wireless"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modalità Debug quando il Wi-Fi è connesso"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modalità debug quando il Wi-Fi è connesso"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Errore"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Debug wireless"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Per trovare e utilizzare i dispositivi disponibili, attiva il debug wireless"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Accoppia il dispositivo con il codice QR"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Accoppia dispositivo con codice QR"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Accoppia i nuovi dispositivi utilizzando lo scanner di codici QR"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Accoppia dispositivo con codice di accoppiamento"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Accoppia i nuovi dispositivi utilizzando un codice di sei cifre"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opzioni per la certificazione display wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta livello di logging Wi-Fi, mostra SSID RSSI nel selettore Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Riduce il consumo della batteria e migliora le prestazioni della rete"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Questa opzione influenza il comportamento della randomizzazione MAC solo nella modalità client.\nQuando questa modalità è attiva, durante l\'associazione gli indirizzi MAC di tutte le reti con randomizzazione MAC abilitata potrebbero essere nuovamente sottoposti a randomizzazione, a seconda di quando il client è stato disconnesso l\'ultima volta dalla rete. La randomizzazione non viene eseguita nuovamente se il dispositivo si riconnette entro quattro ore."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che si connette a una rete con randomizzazione MAC attivata."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"A consumo"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non a consumo"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Dimensioni buffer logger"</string>
@@ -359,7 +359,7 @@
<string name="track_frame_time" msgid="522674651937771106">"Rendering HWUI profilo"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Attiva livelli debug GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Consenti caricamento livelli debug GPU per app di debug"</string>
- <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Attiva reg. dettagl. fornitori"</string>
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Attiva log dettagliati fornitori"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Includi log aggiuntivi di fornitori relativi a un dispositivo specifico nelle segnalazioni di bug che potrebbero contenere informazioni private, causare un maggior consumo della batteria e/o utilizzare più spazio di archiviazione."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Scala animazione finestra"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Scala animazione transizione"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostra finestra di dialogo ANR per app in background"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostra avvisi canale di notifica"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viene mostrato un avviso sullo schermo quando un\'app pubblica una notifica senza un canale valido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Applica scorciatoie per notifiche delle conversazioni"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Richiedi il supporto di una scorciatoia di condivisione di lunga durata per la visualizzazione delle notifiche nella sezione delle conversazioni"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forza autorizzazione app su memoria esterna"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Consente l\'installazione di qualsiasi app su memoria esterna, indipendentemente dai valori manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Imponi formato modificabile alle attività"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predefinito dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Non attivo"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Devi riavviare il dispositivo per applicare questa modifica. Riavvia ora o annulla."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a7862a1..06111b6 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"מפחית את קצב התרוקנות הסוללה ומשפר את ביצועי הרשת"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"לחצן החלפת המצב משפיע על התנהגות הרנדומיזציה של כתובות MAC במצב לקוח בלבד.\nכשמצב זה מופעל, ברשת שבה מופעלת רנדומיזציה של כתובות MAC, ייתכן שתתבצע רנדומיזציה מחדש של כתובות ה-MAC במהלך השיוך, בהתאם למועד הניתוק האחרון של הלקוח מהרשת. לא תתבצע רנדומיזציה מחדש אם המכשיר מתחבר מחדש תוך ארבע שעות או פחות."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"כשמצב זה מופעל, כתובת ה-MAC של המכשיר הזה עשויה להשתנות בכל פעם שהוא מתחבר לרשת שפועלת בה רנדומיזציה של כתובות MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"נמדדת"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"לא נמדדת"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"גדלי מאגר של יומן רישום"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"הצגת תיבת דו-שיח של \'אפליקציה לא מגיבה\' עבור אפליקציות שפועלות ברקע"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"אזהרות לגבי ערוץ התראות"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"הצגת אזהרה כשאפליקציה שולחת התראה ללא ערוץ חוקי"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"אילוץ קיצורי דרך להתראות על שיחות"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"כדי שההודעות יופיעו בקטע השיחות, יש צורך בגיבוי שלהן באמצעות קיצור דרך לשיתוף בעל מחזור חיים ארוך"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"אילוץ הרשאת אפליקציות באחסון חיצוני"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"אלץ יכולת קביעת גודל של הפעילויות"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח"</string>
<string name="guest_nickname" msgid="6332276931583337261">"אורח"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9947b18..850fd97 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ワイヤレス ディスプレイ認証のオプションを表示"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ログレベルを上げて、Wi-Fi 選択ツールで SSID RSSI ごとに表示します"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"電池の消耗が軽減され、ネットワーク パフォーマンスが改善されます"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"この切り替えは、クライアント モードの MAC のランダム化動作にのみ影響します。\nこのモードがアクティブの場合、MAC のランダム化が有効になっているすべてのネットワークで、クライアントがネットワークから最後に切断されたタイミングに応じて、関連付けの際に MAC アドレスが再ランダム化されることがあります。再ランダム化は、デバイスが 4 時間以内に再接続された場合は行われません。"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"このモードが有効な場合、このデバイスは、MAC アドレスのランダム化が有効なネットワークに接続するたびに MAC アドレスが変わる可能性があります。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"従量制"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"定額制"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ログバッファのサイズ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"バックグラウンド アプリが応答しない場合にダイアログを表示"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"通知チャネルの警告を表示"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"アプリから有効なチャネルのない通知が投稿されたときに画面上に警告を表示します"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"会話通知用のショートカット"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"会話セクションに表示されるように、通知が長期の共有ショートカットに対応することを要件とします"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"外部ストレージへのアプリの書き込みを許可"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"アクティビティをサイズ変更可能にする"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ゲスト"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 5240b0c..025cd94 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ამცირებს ბატარეის ხარჯვას და აუმჯობესებს ქსელის მუშაობას"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ეს გადასართავი მხოლოდ კლიენტის რეჟიმში მოქმედებს MAC მისამართის შემთხვევითობაზე.\nამ რეჟიმის გააქტიურების შემთხვევაში, ნებისმიერმა ქსელმა, რომლისთვისაც MAC მისამართის შემთხვევითობა ჩართულია, შეიძლება ხელახლა მოახდინოს MAC მისამართთა შემთხვევითობის განხორციელება დაკავშირებისას, იმის გათვალისწინებით, თუ როდის გაწყვიტა კლიენტმა ბოლოს ქსელთან კავშირი. შემთხვევითობა აღარ განმეორდება, თუ ეს მოწყობილობა ქსელს 4 საათის ფარგლებში ან უფრო ნაკლებ დროში დაუკავშირდება."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"როდესაც ეს რეჟიმი ჩართულია, მოწყობილობის MAC მისამართი შეიძლება შეიცვალოს ისეთ ქსელთან ყოველ დაკავშირებაზე, რომელსაც ჩართული აქვს MAC მისამართის შემთხვევითობა."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ლიმიტირებული"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"არალიმიტირებული"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ჟურნალიზაციის ბუფერის ზომები"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"„აპი არ რეაგირებს“ შეტყობინების ჩვენება, როცა ფონური აპლიკაცია არ პასუხობს"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"შეტყობინებათა არხის გაფრთხილებების ჩვენება"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ეკრანზე აჩვენებს გაფრთხილებას, როცა აპი შეტყობინებას სწორი არხის გარეშე განათავსებს"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"მალსახმობების მოთხოვნა მიმოწერის შეტყობინებებისთვის"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"მოითხოვეთ, შეტყობინებები ეყრდნობოდეს ხანგრძლივად არსებულ გაზიარების მალსახმობებს მიმოწერის სექციაში გამოსაჩენად"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"აპების დაშვება გარე მეხსიერებაში"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"აპები ჩაიწერება გარე მეხსიერებაზე აღწერის ფაილების მნიშვნელობების მიუხედავად"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ზომაცვლადი აქტივობების იძულება"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string>
<string name="guest_nickname" msgid="6332276931583337261">"სტუმარი"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 84d0bb6..9bcc0a2 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -203,9 +203,9 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN параметрлері осы пайдаланушы үшін қол жетімді емес"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Тетеринг параметрлері осы пайдаланушы үшін қол жетімді емес"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Кіру нүктесі атауының параметрлері осы пайдаланушы үшін қол жетімді емес"</string>
- <string name="enable_adb" msgid="8072776357237289039">"USB жөндеу"</string>
- <string name="enable_adb_summary" msgid="3711526030096574316">"USB жалғанғандағы жөндеу режимі"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"USB жөндеу рұқсаттарынан бас тарту"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"USB арқылы түзету"</string>
+ <string name="enable_adb_summary" msgid="3711526030096574316">"USB жалғанғандағы түзету режимі"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"USB арқылы түзету рұқсаттарынан бас тарту"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Сымсыз түзету"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi желісіне жалғанған кездегі түзету режимі"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Қате"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Сымсыз дисплей сертификаты опцияларын көрсету"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi тіркеу деңгейін арттыру, Wi‑Fi таңдағанда әр SSID RSSI бойынша көрсету"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарея зарядының шығынын азайтады және желі жұмысын жақсартады."</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Бұл қосқыш тек клиент режимі үшін MAC рандомизациясының әрекетіне әсер етеді.\nБұл режим қосылған кезде, MAC рандомизациясы қосулы кез келген желі MAC мекенжайларын қайта рандомизациялайды. Бұл үшін клиенттің желіден ең соңғы ажыратылған уақыты негізге алынады. Құрылғы желіге 4 сағат немесе одан аз уақыт ішінде қайта қосылса, қайта рандомизацияланбайды."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Бұл режим қосулы болса, құрылғының MAC мекенжайы MAC рандомизациясы қосулы желіге жалғанған сайын өзгеруі мүмкін."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Трафик саналады"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Трафик саналмайды"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Журналға тіркеуші буферінің өлшемдері"</string>
@@ -300,11 +300,11 @@
<string name="debug_view_attributes" msgid="3539609843984208216">"Көру төлсипатын тексеруді қосу"</string>
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Wi‑Fi қосулы кезде де мобильдік интернетті өшірмеу (желіні жылдам ауыстыру үшін)"</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Тетеринг режиміндегі аппараттық жеделдетуді пайдалану (қолжетімді болса)"</string>
- <string name="adb_warning_title" msgid="7708653449506485728">"USB жөндеулеріне рұқсат берілсін бе?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"USB жөндеу дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және тіркелім деректерін оқу үшін қолданыңыз."</string>
+ <string name="adb_warning_title" msgid="7708653449506485728">"USB арқылы түзетуге рұқсат берілсін бе?"</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"USB арқылы түзету дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және журнал деректерін оқу үшін қолданыңыз."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Сымсыз түзетуге рұқсат берілсін бе?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"Сымсыз түзету функциясы дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және журнал деректерін оқу үшін қолданыңыз."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"Бұған дейін рұқсат берілген барлық компьютерлерде USB жөндеу функциясына тыйым салынсын ба?"</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"Бұған дейін рұқсат берілген барлық компьютерлерде USB арқылы түзету функциясына тыйым салынсын ба?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Жетілдіру параметрлеріне рұқсат берілсін бе?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бұл параметрлер жетілдіру мақсатында ғана қолданылады. Олар құрылғыңыз бен қолданбаларыңыздың бұзылуына немесе әдеттен тыс әрекеттерге себеп болуы мүмкін."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB арқылы орнатылған қолданбаларды растау"</string>
@@ -317,10 +317,10 @@
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP тексеру"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP (кең жолақты сандық мазмұн қорғау) тексеру мүмкіндігін орнату"</string>
- <string name="debug_debugging_category" msgid="535341063709248842">"Жөндеу"</string>
+ <string name="debug_debugging_category" msgid="535341063709248842">"Түзету"</string>
<string name="debug_app" msgid="8903350241392391766">"Жөндеу қолданбасын таңдау"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Жөндеу қолданбалары орнатылмаған"</string>
- <string name="debug_app_set" msgid="6599535090477753651">"Жөндеу қолданбасы: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_app_set" msgid="6599535090477753651">"Түзету қолданбасы: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="2543228890535466325">"Қолданба таңдау"</string>
<string name="no_application" msgid="9038334538870247690">"Ешнәрсе"</string>
<string name="wait_for_debugger" msgid="7461199843335409809">"Жөндеушіні күту"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Фондық қолданбалар үшін \"Қолданба жауап бермейді\" терезесін шығару"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Хабарландыру арнасының ескертулерін көрсету"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Қолданба жарамсыз арна арқылы хабарландыру жариялағанда, экранға ескерту шығарады"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Чат хабарландырулары үшін таңбашаларды пайдалану"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Хабарландырулар чат бөлімінде көрсетілуі үшін, оларды ұзақ көрсетілетін таңбаша арқылы міндетті түрде қайталап көрсету"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Сыртқы жадта қолданбаларға рұқсат ету"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест мәндеріне қарамастан, кез келген қолданбаны сыртқы жадқа жазу мүмкіндігін береді"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Әрекеттердің өлшемін өзгертуге рұқсат ету"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index f1e42db..ce03f22 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"បង្ហាញជម្រើសសម្រាប់សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"បង្កើនកម្រិតកំណត់ហេតុ Wi-Fi បង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសរើស Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"កាត់បន្ថយការប្រើប្រាស់ថ្ម និងកែលម្អប្រតិបត្តិការបណ្ដាញ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ការបិទ/បើកនេះប៉ះពាល់ដល់សកម្មភាពតម្រៀប MAC តាមលំដាប់ចៃដន្យសម្រាប់មុខងារភ្ញៀវតែប៉ុណ្ណោះ។\nនៅពេលបើកដំណើរការមុខងារនេះ បណ្ដាញទាំងឡាយដែលបានបើកការតម្រៀប MAC តាមលំដាប់ចៃដន្យប្រហែលជាត្រូវបានតម្រៀបអាសយដ្ឋាន MAC របស់វាតាមលំដាប់ចៃដន្យឡើងវិញ អំឡុងពេលភ្ជាប់ ដោយផ្អែកលើពេលវេលាដែលមុខងារភ្ញៀវបានផ្ដាច់លើកចុងក្រោយពីបណ្ដាញ។ ការតម្រៀបតាមលំដាប់ចៃដន្យឡើងវិញមិនកើតឡើងទេ ប្រសិនបើឧបករណ៍ភ្ជាប់ឡើងវិញក្នុងរយៈពេល 4 ម៉ោង ឬឆាប់ជាងនេះ។"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"នៅពេលបើកមុខងារនេះ អាសយដ្ឋាន MAC របស់ឧបករណ៍នេះអាចផ្លាស់ប្ដូរ រាល់ពេលដែលវាភ្ជាប់ជាមួយបណ្ដាញដែលបានបើកការតម្រៀប MAC តាមលំដាប់ចៃដន្យ។"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"មានការកំណត់"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"មិនមានការកំណត់"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ទំហំកន្លែងផ្ទុករបស់ logger"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"បង្ហាញប្រអប់កម្មវិធីមិនឆ្លើយតបសម្រាប់កម្មវិធីផ្ទៃខាងក្រោយ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"បង្ហាញការព្រមានអំពីបណ្តាញជូនដំណឹង"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"បង្ហាញការព្រមាននៅលើអេក្រង់ នៅពេលកម្មវិធីបង្ហោះការជូនដំណឹងដោយមិនមានបណ្តាញត្រឹមត្រូវ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ជំរុញឱ្យប្រើផ្លូវកាត់សម្រាប់ការជូនដំណឹងពីការសន្ទនា"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"តម្រូវឱ្យបម្រុងទុកការជូនដំណឹង តាមរយៈផ្លូវកាត់ចែករំលែកដែលមានអាយុកាលយូរទើបអាចបង្ហាញនៅក្នុងផ្នែកនៃការសន្ទនាបាន"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"បង្ខំឲ្យអនុញ្ញាតកម្មវិធីលើឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"លុបភ្ញៀវ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 5e60928..52e3b99 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ಬ್ಯಾಟರಿ ಹೆಚ್ಚು ಬಾಳಿಕೆ ಬರುವಂತೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ನೆಟ್ವರ್ಕ್ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸುತ್ತದೆ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ಈ ಟಾಗಲ್, ಕ್ಲೈಂಟ್ ಮೋಡ್ಗಾಗಿ ಮಾತ್ರ MAC ಯಾದೃಚ್ಛಿಕರಣ ವರ್ತನೆಯ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ.\nಈ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, MAC ಯಾದೃಚ್ಛಿಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ ಸಂಯೋಜನೆಯನ್ನು ಸ್ಥಾಪಿಸುವಾಗ MAC ವಿಳಾಸವನ್ನು ಮರು-ಯಾದೃಚ್ಛಿಕರಣಗೊಳಿಸಬಹುದು (ಕ್ಲೈಂಟ್ ಕೊನೆಯದಾಗಿ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿರುವುದನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ). ಸಾಧನವು 4 ಗಂಟೆಗಳು ಅಥವಾ ಕಡಿಮೆ ಸಮಯದಲ್ಲಿ ಮರುಸಂಪರ್ಕಿಸಿದರೆ, ಯಾವುದೇ ಮರು-ಯಾದೃಚ್ಛಿಕರಣ ಸಂಭವಿಸುವುದಿಲ್ಲ."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ಈ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, ಪ್ರತಿ ಬಾರಿ MAC ಯಾದೃಚ್ಛಿಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿದಾಗ ಈ ಸಾಧನದ MAC ವಿಳಾಸವು ಬದಲಾಗಬಹುದು."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ಮೀಟರ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ಮೀಟರ್ ಮಾಡಲಾಗಿಲ್ಲ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ಲಾಗರ್ ಬಫರ್ ಗಾತ್ರಗಳು"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ಹಿನ್ನೆಲೆ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ ಎಂಬ ಸಂಭಾಷಣೆ ತೋರಿಸಿ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ಅಧಿಸೂಚನೆ ಎಚ್ಚರಿಕೆ ತೋರಿಸಿ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ಅಮಾನ್ಯ ಚಾನಲ್ ಅಧಿಸೂಚನೆಗಾಗಿ ಪರದೆಯಲ್ಲಿ ಎಚ್ಚರಿಕೆ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳಿಗಾಗಿ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಜಾರಿಗೊಳಿಸಿ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ಸಂಭಾಷಣೆ ವಿಭಾಗದಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳಲು, ಅಧಿಸೂಚನೆಗಳನ್ನು ದೀರ್ಘಕಾಲದ ಹಂಚಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಮೂಲಕ ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 7c20c94..b95ad9b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -210,7 +210,7 @@
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi가 연결되었을 때 디버그 모드 사용"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"오류"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"무선 디버깅"</string>
- <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"사용 가능한 기기를 보고 사용하려면 무선 디버깅을 사용 설정하세요."</string>
+ <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"사용 가능한 기기를 확인하고 사용하려면 무선 디버깅을 사용 설정하세요."</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR 코드로 기기 페어링"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR 코드 스캐너를 사용하여 새 기기 페어링"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"페어링 코드로 기기 페어링"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"무선 디스플레이 인증서 옵션 표시"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"배터리 소모를 줄이고 네트워크 성능 개선"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"이 전환은 클라이언트 모드의 MAC 무작위 순서 지정 방식에만 영향을 줍니다.\n이 모드를 활성화하면 네트워크와 클라이언트 연결이 끊긴 마지막 시점에 따라 MAC 무작위 순서 지정이 사용 설정된 네트워크에서 연결 중에 MAC 주소를 다시 무작위 순서로 지정할 수 있습니다. 기기가 4시간 이내에 재연결된 경우 무작위 순서 지정이 다시 발생하지 않습니다."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"이 모드를 사용 설정하면 기기가 MAC 주소 무작위 지정이 설정된 네트워크에 연결될 때마다 기기의 MAC 주소가 변경될 수 있습니다."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"종량제 네트워크"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"무제한 네트워크"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"로거 버퍼 크기"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"백그라운드 앱과 관련해 앱 응답 없음 대화상자 표시"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"알림 채널 경고 표시"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"앱에서 유효한 채널 없이 알림을 게시하면 화면에 경고 표시"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"대화 알림에 단축키 적용"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"알림이 대화 섹션에 표시되려면 오래 지속되는 공유 단축키의 지원을 받도록 요구"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"외부에서 앱 강제 허용"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"매니페스트 값과 관계없이 모든 앱이 외부 저장소에 작성되도록 허용"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"활동의 크기가 조정 가능하도록 설정"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
<string name="guest_nickname" msgid="6332276931583337261">"게스트"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8ec5f3a..45fc6cb 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -203,29 +203,29 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"Бул колдонуучу VPN жөндөөлөрүн колдоно албайт"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу модем режиминин жөндөөлөрүн өзгөртө албайт"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Бул колдонуучу мүмкүндүк алуу түйүнүнүн аталышынын жөндөөлөрүн колдоно албайт"</string>
- <string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү оңдоо"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB компьютерге сайылганда мүчүлүштүктөрдү оңдоо режими иштейт"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү оңдоо уруксатын артка кайтаруу"</string>
- <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi\'га туташтырылганда мүчүлүштүктөрдү оңдоо режими"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү аныктоо уруксатын артка кайтаруу"</string>
+ <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi\'га туташканда, мүчүлүштүктөрдү аныктоо режими иштейт оңдоо режими"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Ката"</string>
- <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string>
- <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн мүчүлүштүктөрдү Wi-Fi аркылуу оңдоону күйгүзүңүз"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR кодун колдонуп, түзмөктү жупташтырыңыз"</string>
+ <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо"</string>
+ <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн, мүчүлүштүктөрдү Wi-Fi аркылуу аныктоону күйгүзүңүз"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Түзмөктү QR коду аркылуу жупташтыруу"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодунун сканерин колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Жупташтыруучу код менен түзмөктү жупташтырыңыз"</string>
- <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Алты сандан турган кодду колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Түзмөктү атайын код аркылуу жупташтыруу"</string>
+ <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Жаңы түзмөктөрдү алты сандан турган код аркылуу жупташтырасыз"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Жупташтырылган түзмөктөр"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Учурда туташып турган түзмөктөр"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Түзмөктүн чоо-жайы"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Унутулсун"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Түзмөктөгү манжа изи: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
- <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Туташкан жок"</string>
+ <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Байланышкан жок"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> туура тармакка туташып турганын текшериңиз"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Түзмөктү жупташтыруу"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi жупташтыруучу коду"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Жупташтырылган жок"</string>
- <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Түзмөк бир тармакка туташканын текшериңиз."</string>
+ <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>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Зымсыз мониторлорду тастыктамалоо параметрлери көрүнүп турат"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi тандалганда ар бир SSID үчүн RSSI көрүнүп турат"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батареянын коротулушун чектеп, тармактын иштешин жакшыртат"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Бул жөндөөнүн өчүрүлүшү/күйгүзүлүшү MAC даректерин башаламан түзүү тартибине кардар режиминде гана таасирин тийгизет.\nБул режим иштетилсе, MAC даректерин башаламан түзүү иштетилген бардык тармактарда байланышуу учурунда, кардар тармактан акыркы жолу качан ажыратылганына жараша, алардын MAC даректери кайрадан башаламан түзүлүшү мүмкүн. Эгер түзмөк 4 саатка жетпеген убакытта кайра туташтырылса, даректерди башаламан түзүү аракети аткарылбайт."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Бул режим өчүрүлгөндөн кийин түзмөк MAC даректи башаламан иретте түзүү функциясы иштетилген тармакка туташкан сайын анын MAC дареги өзгөрүшү мүмкүн."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Трафик ченелет"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Чектелбеген тармак"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферинин өлчөмү"</string>
@@ -303,7 +303,7 @@
<string name="adb_warning_title" msgid="7708653449506485728">"USB аркылуу жөндөөгө уруксат бересизби?"</string>
<string name="adb_warning_message" msgid="8145270656419669221">"USB-жөндөө - өндүрүү максатында гана түзүлгөн. Аны компүтериңиз менен түзмөгүңүздүн ортосунда берилиштерди алмашуу, түзмөгүңүзгө колдонмолорду эскертүүсүз орнотуу жана лог берилиштерин окуу үчүн колдонсоңуз болот."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилсинби?"</string>
- <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string>
+ <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу аныктоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"Сиз мурун USB жөндөөлөрүнө уруксат берген бардык компүтерлердин жеткиси жокко чыгарылсынбы?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Жөндөөлөрдү өзгөртүү"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
@@ -317,7 +317,7 @@
<string name="enable_terminal_summary" msgid="2481074834856064500">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP текшерүү"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP текшерүү тартиби"</string>
- <string name="debug_debugging_category" msgid="535341063709248842">"Мүчүлүштүктөрдү оңдоо"</string>
+ <string name="debug_debugging_category" msgid="535341063709248842">"Мүчүлүштүктөрдү аныктоо"</string>
<string name="debug_app" msgid="8903350241392391766">"Мүчүлүштүктөрдү оңдоочу колдонмону тандоо"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Бир дагы колдонмо орнотула элек."</string>
<string name="debug_app_set" msgid="6599535090477753651">"Жөндөөчү колдонмо: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -360,7 +360,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU мүчүлүштүктөрдү оңдоо катмарларын иштетүү"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"GPU мүчүлүштүктөрдү оңдоо катмарларын иштетет"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Кызмат көрсөтүүчүнү оозеки киргизүүнү иштетет"</string>
- <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Түзмөккө байланыштуу кызмат көрсөтүүчүнүн кирүүлөрү боюнча мүчүлүштүк тууралуу кабар берүү камтылсын. Анда купуя маалымат көрсөтүлүп, батарея тезирээк отуруп жана/же сактагычтан көбүрөөк орун ээлениши мүмкүн."</string>
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Түзмөккө байланыштуу кызмат көрсөтүүчүнүн кирүүлөрү боюнча мүчүлүштүк тууралуу кабарлоо камтылсын. Анда купуя маалымат көрсөтүлүп, батарея тезирээк отуруп жана/же сактагычтан көбүрөөк орун ээлениши мүмкүн."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Терезелердин анимациясы"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Өткөрүү анимацснн шкаласы"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Анимациянын узактыгы"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Фондогу колдонмо жооп бербей жатат деп билдирип турат"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Билдирмелер каналынын эскертүүлөрүн көрсөтүү"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Тыюу салынган каналдын колдонмосунун жаңы билдирмелери тууралуу эскертүүлөр көрүнөт"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Жазышуу билдирмелери үчүн ыкчам баскычтарды иштетиңиз"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Жазышуу бөлүмүндө көрсөтүү үчүн билдирмелерди узак убакытка колдонулуучу ыкчам баскычтар менен колдоону талап кылыңыз"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Тышкы сактагычка сактоого уруксат берүү"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Бир нече терезе режиминде өлчөмдү өзгөртүү"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Конок"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 1fb181d..4e39674 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -203,9 +203,9 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"ຜູ່ໃຊ້ນີ້ບໍ່ສາມາດຕັ້ງຄ່າ VPN ໄດ້"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"ຜູ່ໃຊ້ນີ້ບໍ່ສາມາດຕັ້ງຄ່າການປ່ອຍສັນຍານໄດ້"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"ຜູ່ໃຊ້ນີ້ບໍ່ສາມາດຕັ້ງຄ່າຊື່ເອດເຊສພອຍໄດ້"</string>
- <string name="enable_adb" msgid="8072776357237289039">"ການດີບັ໊ກຜ່ານ USB"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"ການດີບັກຜ່ານ USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"ເປີດໃຊ້ໂໝດດີບັ໊ກເມື່ອເຊື່ອມຕໍ່ USB"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"ຖອດຖອນການອະນຸຍາດການດີບັ໊ກຜ່ານ USB"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"ຖອດຖອນການອະນຸຍາດການດີບັກຜ່ານ USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"ການດີບັກໄຮ້ສາຍ"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"ໂໝດດີບັກເມື່ອເຊື່ອມຕໍ່ Wi‑Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"ຜິດພາດ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ຫຼຸດການໃຊ້ແບັດເຕີຣີ ແລະ ປັບປຸງປະສິດທິພາບເຄືອຂ່າຍ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ການເປີດ/ປິດນີ້ຈະມີຜົນກັບພຶດຕິກຳການສຸ່ມ MAC ສຳລັບໂໝດລູກຂ່າຍເທົ່ານັ້ນ.\nເມື່ອເປີດໃຊ້ໂໝດນີ້, ເຄືອຂ່າຍໃດກໍຕາມທີ່ເປີດການນຳໃຊ້ການສຸ່ມ MAC ອາດສຸ່ມທີ່ຢູ່ MAC ຂອງເຂົາເຈົ້າຄືນໃໝ່ໃນລະຫວ່າງການເຊື່ອມໂຍງ, ຂຶ້ນກັບວ່າລູກຂ່າຍຕັດການເຊື່ອມຕໍ່ຈາກເຄືອຂ່າຍຫຼ້າສຸດຕອນໃດ. ການສຸ່ມໃໝ່ຈະບໍ່ເກີດຂຶ້ນຫາກອຸປະກອນເຊື່ອມຕໍ່ຄືນໃໝ່ພາຍໃນ 4 ຊົ່ວໂມງ ຫຼື ໜ້ອຍກວ່ານັ້ນ."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ຫາກເປີດການນຳໃຊ້ໂໝດນີ້, ທີ່ຢູ່ MAC ຂອງອຸປະກອນນີ້ອາດມີການປ່ຽນແປງໃນແຕ່ລະເທື່ອທີ່ມັນເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍໃດໜຶ່ງທີ່ເປີດການນຳໃຊ້ການສຸ່ມ MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ມີການວັດແທກ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ບໍ່ໄດ້ວັດແທກ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ຂະໜາດບັບເຟີຕົວບັນທຶກ"</string>
@@ -300,11 +300,11 @@
<string name="debug_view_attributes" msgid="3539609843984208216">"ເປີດນຳໃຊ້ການກວດສອບຄຸນສົມບັດມຸມມອງ"</string>
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືໄວ້ຕະຫຼອດ, ເຖິງແມ່ນວ່າ Wi-Fi ຈະເຮັດວຽກຢູ່ກໍຕາມ (ສຳລັບການສະຫຼັບເຄືອຂ່າຍແບບໄວ)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວຫາກວ່າສາມາດໃຊ້ໄດ້"</string>
- <string name="adb_warning_title" msgid="7708653449506485728">"ອະນຸຍາດໃຫ້ດີບັ໊ກຜ່ານ USB?"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"ການດີບັ໊ກຜ່ານ USB ແມ່ນມີຈຸດປະສົງເພື່ອການພັດທະນາເທົ່ານັ້ນ. ມັນສາມາດໃຊ້ເພື່ອສຳເນົາຂໍ້ມູນລະຫວ່າງຄອມພິວເຕີ ແລະອຸປະກອນຂອງທ່ານ, ຕິດຕັ້ງແອັບຯໂດຍບໍ່ຜ່ານການແຈ້ງເຕືອນ ແລະອ່ານຂໍ້ມູນການບັນທຶກ."</string>
+ <string name="adb_warning_title" msgid="7708653449506485728">"ອະນຸຍາດໃຫ້ດີບັກຜ່ານ USB?"</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"ການດີບັກຜ່ານ USB ແມ່ນມີຈຸດປະສົງເພື່ອການພັດທະນາເທົ່ານັ້ນ. ມັນສາມາດໃຊ້ເພື່ອສຳເນົາຂໍ້ມູນລະຫວ່າງຄອມພິວເຕີ ແລະອຸປະກອນຂອງທ່ານ, ຕິດຕັ້ງແອັບຯໂດຍບໍ່ຜ່ານການແຈ້ງເຕືອນ ແລະອ່ານຂໍ້ມູນການບັນທຶກ."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"ອະນຸຍາດການດີບັກໄຮ້ສາຍບໍ?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"ການດີບັກໄຮ້ສາຍແມ່ນມີຈຸດປະສົງສຳລັບການພັດທະນາເທົ່ານັ້ນ. ມັນສາມາດໃຊ້ເພື່ອສຳເນົາຂໍ້ມູນລະຫວ່າງຄອມພິວເຕີ ແລະ ອຸປະກອນຂອງທ່ານ, ຕິດຕັ້ງແອັບໂດຍບໍ່ຜ່ານການແຈ້ງເຕືອນ ແລະ ອ່ານຂໍ້ມູນບັນທຶກ."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"ຖອດຖອນການເຂົ້າເຖິງການດີບັ໊ກຜ່ານ USB ຈາກຄອມພິວເຕີທຸກເຄື່ອງ ທີ່ທ່ານເຄີຍອະນຸຍາດກ່ອນໜ້ານີ້?"</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"ຖອດຖອນການເຂົ້າເຖິງການດີບັກຜ່ານ USB ຈາກຄອມພິວເຕີທຸກເຄື່ອງ ທີ່ທ່ານເຄີຍອະນຸຍາດກ່ອນໜ້ານີ້?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"ອະນຸຍາດການຕັ້ງຄ່າສຳລັບນັກພັດທະນາ?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"ການຕັ້ງຄ່າເຫຼົ່ານີ້ແມ່ນມີຈຸດປະສົງເພື່ອການພັດທະນາເທົ່ານັ້ນ. ພວກມັນສາມາດເຮັດໃຫ້ອຸປະກອນ ແລະແອັບພລິເຄຊັນຂອງທ່ານຢຸດເຮັດວຽກ ຫຼືເຮັດວຽກຜິດປົກກະຕິໄດ້."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"ຢືນຢັນແອັບຜ່ານທາງ USB"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ສະແດງກ່ອງຂໍ້ຄວາມບໍ່ຕອບສະໜອງແອັບສຳລັບແອັບພື້ນຫຼັງ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ສະແດງຄຳເຕືອນຊ່ອງການແຈ້ງເຕືອນ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ສະແດງຄຳເຕືອນໃນໜ້າຈໍເມື່ອແອັບໂພສການແຈ້ງເຕືອນໂດຍບໍ່ມີຊ່ອງທີ່ຖືກຕ້ອງ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ບັງຄັບໃຊ້ທາງລັດສຳລັບການແຈ້ງເຕືອນການສົນທະນາ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ຕ້ອງໃຊ້ການແຈ້ງເຕືອນເພື່ອຮັບການສະໜັບສະໜຸນໂດຍທາງລັດການແບ່ງປັນທີ່ຢູ່ດົນເພື່ອໃຫ້ປາກົດໃນພາກສ່ວນການສົນທະນາ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ບັງຄັບອະນຸຍາດແອັບຢູ່ພາຍນອກ"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ບັງຄັງໃຫ້ການເຄື່ອນໄຫວປ່ຽນຂະໜາດໄດ້"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ແຂກ"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"ຄ່າເລີ່ມຕົ້ນອຸປະກອນ"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ປິດການນຳໃຊ້ແລ້ວ"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index cc43d5a..81357cc 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sumažinamas akumuliatoriaus eikvojimas ir patobulinamas tinklo našumas"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Perjungiamas tik atsitiktinis MAC adreso parinkimas dirbant kliento režimu.\nKai suaktyvintas šis režimas, visuose tinkluose, kuriuose įgalintas atsitiktinis MAC adreso parinkimas, susiejant šie adresai gali būti atsitiktinai parenkami iš naujo, atsižvelgiant į tai, kada klientas paskutinį kartą atsijungė nuo tinklo. Atsitiktinis MAC adreso parinkimas nevykdomas iš naujo, jei įrenginys vėl prisijungia ne daugiau nei po keturių valandų."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kai įgalintas šis režimas, šio įrenginio MAC adresas gali keistis kas kartą prisijungus prie tinklo, kuriame įgalintas atsitiktinis MAC parinkimas."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Matuojamas"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Neišmatuotas"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Registruotuvo buferio dydžiai"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Foninėse programose rodyti dialogo langą „Programa neatsako“"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Rodyti pran. kan. įspėj."</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Ekr. rod. įsp., kai progr. pask. pr. be tink. kan."</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Nustatyti pokalbio pranešimų šaukinius"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kad pranešimai būtų rodomi pokalbių skiltyje, būtinas ilgalaikis jų bendrinimo šaukinys"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Priverstinai leisti programas išorinėje atmintin."</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Nustatoma, kad visas programas būtų galima įrašyti į išorinę saugyklą, nepaisant aprašo verčių"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 1fa3c08..c63f312 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Samazina akumulatora izlādi un uzlabo tīkla veiktspēju"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Šis slēdzis ietekmē MAC adrešu nejaušas izveides darbību tikai klienta režīmā.\nJa šis režīms ir aktivizēts, visos tīklos, kuros MAC adrešu nejauša izveide ir iespējota, saistīšanas laikā MAC adreses var tikt atkārtoti nejauši izveidotas atkarībā no tā, kad klients pēdējoreiz pārtrauca savienojumu ar tīklu. Atkārtota nejauša izveide netiek veikta, ja ierīces savienojums tiek atjaunots ne vairāk kā 4 stundu laikā."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ja šis režīms ir iespējots, šīs ierīces MAC adrese var mainīties ikreiz, kad ierīcē tiek izveidots savienojums ar tīklu, kurā ir iespējota MAC adrešu nejauša izveide."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Maksas"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bezmaksas"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Reģistrētāja buferu lielumi"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Rādīt fona lietotņu dialoglodziņu Lietotne nereaģē"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Paziņojumu kanāla brīdinājumi"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Brīdinājums ekrānā, kad lietotne publicē paziņojumu, nenorādot derīgu kanālu"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Ieviest saīsnes sarunu paziņojumiem"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Pieprasīt izmantot paziņojumiem ilgstošas darbības kopīgošanas saīsni rādīšanai sarunu sadaļā"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Lietotņu piespiedu atļaušana ārējā krātuvē"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Pielāgot darbības"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 1e2c741..e0cc38d 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Покажи ги опциите за безжичен приказ на сертификат"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Го намалува искористувањето на батеријата и ја подобрува изведбата на мрежата"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Овој прекинувач влијае на однесувањето на рандомизацијата на MAC само за клиентски режим.\nКога е активиран режимов, можно е да се изврши повторна рандомизација на MAC-адресите на сите мрежи што имаат овозможена рандомизација на MAC за време на асоцијацијата, зависно од тоа кога клиентот последен пат се исклучил од мрежата. Повторната рандомизација не се случува ако уредот се поврзе повторно во рок од 4 часа или помалку."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Кога е овозможен режимов, MAC-адресата на уредов може да се промени секој пат кога ќе се поврзе со мрежа што има овозможена рандомизација на MAC-адреси."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Со ограничен интернет"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничен интернет"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Величини на меѓумеморија за дневникот"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Прикажи го дијалогот „Апликацијата не реагира“ за апликации во заднина"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Прикажи ги предупредувањата на каналот за известувањe"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Предупредува кога апликација дава известување без важечки канал"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Кратенки за известувањата"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Известувања со долготрајна кратенка за споделување"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Принуд. дозволете апликации на надворешна меморија"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Прави секоја апликација да биде подобна за запишување на надворешна меморија, независно од вредностите на манифестот"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Принуди ги активностите да ја менуваат големината"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додај гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Стандардно за уредот"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 156d941..1a3f068 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"അജ്ഞാതം"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ഉപയോക്താവ്: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"സ്ഥിരമായ ചിലത് സജ്ജീകരിച്ചു"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"സ്ഥിരമായൊന്നും സജ്ജീകരിച്ചിട്ടില്ല"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"ഡിഫോൾട്ടുകളൊന്നും സജ്ജീകരിച്ചിട്ടില്ല"</string>
<string name="tts_settings" msgid="8130616705989351312">"ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ക്രമീകരണങ്ങൾ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ടെക്സ്റ്റ്-ടു-സ്പീച്ച് ഔട്ട്പുട്ട്"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"വായനയുടെ വേഗത"</string>
@@ -207,7 +207,7 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"USB കണക്റ്റുചെയ്തിരിക്കുമ്പോഴുള്ള ഡീബഗ് മോഡ്"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB ഡീബഗ്ഗിംഗ് അംഗീകാരം പിൻവലിക്കുക"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"വൈഫൈ കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ ഡീബഗ് ചെയ്യൽ മോഡിലാക്കുക"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"വൈഫൈ കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ ഡീബഗ് മോഡിലാക്കുക"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"പിശക്"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ലഭ്യമായ ഉപകരണങ്ങൾ കാണാനും ഉപയോഗിക്കാനും വയർലെസ് ഡീബഗ്ഗിംഗ് ഓണാക്കുക"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ബാറ്ററി ചാർജ് വേഗത്തിൽ തീരുന്ന അവസ്ഥ കുറച്ച് നെറ്റ്വർക്ക് പ്രകടനം മെച്ചപ്പെടുത്തുന്നു"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ഈ മാറ്റം ക്ലയന്റ് മോഡിലെ MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനരീതിയെ മാത്രമേ ബാധിക്കുകയുള്ളൂ.\nഈ മോഡ് സജീവമാക്കിക്കഴിഞ്ഞാൽ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന എല്ലാ നെറ്റ്വർക്കുകളിലും അസോസിയേഷൻ സമയത്ത്, ക്ലയന്റ് അവസാനമായി നെറ്റ്വർക്കിൽ നിന്ന് വിച്ഛേദിച്ച സമയത്തിന്റെ അടിസ്ഥാനത്തിൽ അവരുടെ MAC വിലാസങ്ങൾ വീണ്ടും ക്രമരഹിതമാക്കപ്പെടും. നാല് മണിക്കൂറോ അതിൽ കുറവ് സമയത്തിനുള്ളിലോ ഉപകരണം വീണ്ടും കണക്റ്റ് ചെയ്യുന്നില്ലെങ്കിൽ വീണ്ടും ക്രമരഹിതമാക്കൽ സംഭവിക്കില്ല."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ഈ മോഡ് പ്രവർത്തനക്ഷമമാക്കുമ്പോൾ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുമ്പോഴെല്ലാം ഈ ഉപകരണത്തിന്റെ MAC വിലാസം മാറിയേക്കാം."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർ ചെയ്തത്"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"മീറ്റർമാപകമല്ലാത്തത്"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ലോഗർ ബഫർ വലുപ്പം"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"പശ്ചാത്തല ആപ്പുകൾക്കായി \'ആപ്പ് പ്രതികരിക്കുന്നില്ല\' ഡയലോഗ് പ്രദര്ശിപ്പിക്കുക"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ചാനൽ മുന്നറിയിപ്പ് കാണിക്കൂ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"സാധുതയുള്ള ചാനലിൽ അല്ലാതെ ഒരു ആപ്പ്, അറിയിപ്പ് പോസ്റ്റ് ചെയ്യുമ്പോൾ ഓൺ-സ്ക്രീൻ മുന്നറിയിപ്പ് പ്രദർശിപ്പിക്കുന്നു"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"സംഭാഷണ അറിയിപ്പിലേക്ക് കുറുക്കുവഴികൾ നടപ്പിലാക്കൂ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"സംഭാഷണ വിഭാഗത്തിൽ ദൃശ്യമാകാൻ അറിയിപ്പുകൾ ദീർഘകാലമായി പങ്കിടൽ കുറുക്കുവഴി പിന്തുടരണം"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ബാഹ്യമായതിൽ നിർബന്ധിച്ച് അനുവദിക്കുക"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"വലുപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 249489e..81733f2 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарей зарцуулалтыг бууруулж, сүлжээний гүйцэтгэлийг сайжруулдаг"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Унтраах эсвэл асаах нь зөвхөн клиент горимын MAC-г санамсаргүй байдлаар эмхлэх төлөвт нөлөөлнө.\nЭнэ горимыг идэвхжүүлсэн тохиолдолд клиентийг сүлжээнээс хамгийн сүүлд хэзээ салгаснаас хамаараад, холбоотой байх үеэр MAC-г санамсаргүй байдлаар эмхлэхийг идэвхжүүлсэн дурын сүлжээний MAC хаягуудыг санамсаргүй байдлаар дахин эмхэлж болзошгүй. Төхөөрөмж 4 цаг буюу түүнээс бага хугацаанд дахин холбогдвол санамсаргүй байдлаар дахин эмхлэх төлөв хэрэгжихгүй."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Энэ горимыг идэхвжүүлсэн үед энэ төхөөрөмжийг MAC-н санамсаргүй байдлаар эмхлэх явцыг идэвхжүүлсэн сүлжээнд холбогдох бүрд үүний MAC хаягийг өөрчилж болзошгүй."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Хязгаартай"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Хязгааргүй"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Логгерын буферын хэмжээ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Апп хариу өгөхгүй байна гэсэн харилцах цонхыг цаана байгаа аппад харуулах"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Мэдэгдлийн сувгийн анхааруулгыг харуулах"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Апп хүчинтэй суваггүйгээр мэдэгдэл гаргах үед дэлгэцэд сануулга харуулна"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Харилцан ярианы мэдэгдлийн товчлолыг хэрэгжүүлэх"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Харилцан ярианы хэсэгт харуулахын тулд санах ойд хадгалсан хуваалцах товчлолоор мэдэгдлийг нөөцлөхийг шаардах"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Аппыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест утгыг нь үл хамааран дурын апп-г гадаад санах ойд бичих боломжтой болгодог"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index b2e4c0a..0895cd4 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -115,11 +115,11 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"पेअर करा"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"पेअर करा"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"रद्द करा"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"कनेक्ट केल्यावर पेअरींग तुमचे संपर्क आणि कॉल इतिहास यामध्ये अॅक्सेस देते."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"कनेक्ट केल्यावर पेअरिंग तुमचे संपर्क आणि कॉल इतिहास यामध्ये अॅक्सेस देते."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी जोडू शकलो नाही."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"अयोग्य पिन किंवा पासकीमुळे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडू शकलो नाही."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संवाद प्रस्थापित करू शकत नाही."</string>
- <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारे पेअरींग नाकारले."</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारे पेअरिंग नाकारले."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"कॉंप्युटर"</string>
<string name="bluetooth_talkback_headset" msgid="3406852564400882682">"हेडसेट"</string>
<string name="bluetooth_talkback_phone" msgid="868393783858123880">"फोन"</string>
@@ -213,7 +213,7 @@
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध डिव्हाइस पाहण्यासाठी आणि वापरण्यासाठी वायरलेस डीबगिंग सुरू करा"</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR कोडसह डिव्हाइस जोडा"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR कोड स्कॅनर वापरून नवीन डिव्हाइस पेअर करा"</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>
@@ -223,7 +223,7 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"कनेक्ट करता आले नाही"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> योग्य नेटवर्कशी कनेक्ट केले असल्याची खात्री करा"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"डिव्हाइससह पेअर करा"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"वाय-फाय पेअरींग कोड"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"वाय-फाय पेअरिंग कोड"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"पेअर करता आले नाही"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"डिव्हाइस समान नेटवर्कशी कनेक्ट केले असल्याची खात्री करा."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR कोड स्कॅन करून वाय-फाय वापरून डिव्हाइस पेअर करा"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय सिलेक्टरमध्ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बॅटरी जलदरीतीने संपण्यापासून रोखते आणि नेटवर्क परफॉर्मन्समध्ये सुधारणा करते"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"या टॉगलचा फक्त क्लायंट मोडसाठी MAC रँडमायझेशन वर्तनावर परिणाम होतो.\nहा मोड अॅक्टिव्हेट केलेला असताना, तुमच्या नेटवर्कवरून क्लायंट शेवटचा कधी डिस्कनेक्ट केला गेला त्यावर अवलंबून, संबद्धीकरणादरम्यान MAC रँडमायझेशन सुरू असलेल्या कोणत्याही नेटवर्कचे MAC अॅड्रेस पुन्हा रँडमाइझ केले जाऊ शकतात. डिव्हाइस चार तासांत किंवा त्यापेक्षा कमी वेळात पुन्हा कनेक्ट झाल्यास पुन्हा रँडमायझेशन होत नाही."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"हा मोड सुरू केला असल्यास, या डिव्हाइसचा MAC अॅड्रेस प्रत्येक वेळी MAC रँडमायझेशन सुरू असलेल्या नेटवर्कशी कनेक्ट झाल्यास, कदाचित बदलू शकतो."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"मीटरने मोजलेले"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मीटरने न मोजलेले"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफर आकार"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"बॅकग्राउंड अॅप्ससाठी अॅप प्रतिसाद देत नाही दाखवते"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना चॅनेल चेतावण्या दाखवा"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"एखादे अॅप वैध चॅनेलशिवाय सूचना पोस्ट करते तेव्हा स्क्रीनवर चेतावणी देते"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"संभाषण सूचना शॉर्टकट ठेवा"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"सूचनांना जुन्या शॉर्टकटचा सपोर्ट आवश्यक"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"बाह्यवर ॲप्सना अनुमती देण्याची सक्ती करा"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"manifest मूल्यांकडे दुर्लक्ष करून, कोणत्याही ॲपला बाह्य स्टोरेजवर लेखन केले जाण्यासाठी पात्र बनविते"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ॲक्टिव्हिटीचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index fa36975..bb70a86 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Mengurangkan penyusutan bateri & meningkatkan prestasi rangkaian"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Togol ini melibatkan gelagat perawakan MAC untuk mod pelanggan sahaja.\nApabila mod ini diaktifkan, alamat MAC bagi mana-mana rangkaian yang telah mendayakan perawakan MAC mungkin dirawakkan semula semasa perkaitan, bergantung pada kali terakhir pelanggan diputuskan sambungan daripada rangkaian. Perawakan semula tidak berlaku jika peranti menyambung semula dalam tempoh 4 jam atau kurang."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Apabila mod ini didayakan, alamat MAC peranti ini mungkin berubah setiap kali peranti bersambung kepada rangkaian yang telah mendayakan perawakan MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Bermeter"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak bermeter"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Saiz penimbal pengelog"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Paparkan dialog Apl Tiada Respons untuk apl latar belakang"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Papar amaran saluran pemberitahuan"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Memaparkan amaran pada skrin apabila apl menyiarkan pemberitahuan tanpa saluran sah"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kuat kuasakan pintasan utk pemberitahuan perbualan"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Perlukan pemberitahuan disokong oleh pintasan perkongsian hayat panjang untuk muncul dalam bahagian perbualan"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Benarkan apl secara paksa pada storan luaran"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Menjadikan sebarang apl layak ditulis ke storan luaran, tanpa mengambil kira nilai manifes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktiviti supaya boleh diubah saiz"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 6719bad..920d659 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ဘက်ထရီ အသုံးပြုမှုကို လျှော့ကျစေပြီး ကွန်ရက်စွမ်းဆောင်ရည်ကို ပိုမိုကောင်းမွန်စေသည်"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ဤဖွင့်ပိတ်ခလုတ်က ကလိုင်းယင့်မုဒ် အတွက်သာ MAC ကျပန်းပြုလုပ်ခြင်း အပြုအမူကို သက်ရောက်စေသည်။\nဤမုဒ်အသုံးပြုသည့်အခါ MAC ကျပန်းပြုလုပ်ခြင်း ဖွင့်ထားသော ကွန်ရက်များသည် ကွန်ရက်မှ ကလိုင်းယင့် ချိတ်ဆက်မှုဖြုတ်သည့် နောက်ဆုံးအချိန်ပေါ် မူတည်၍ ချိတ်ဆက်နေစဉ်အတွင်း ၎င်းတို့၏ MAC လိပ်စာများကို ပြန်လည်ကျပန်းပြုလုပ်နိုင်သည်။ စက်သည် ၄ နာရီအတွင်း ပြန်ချိန်ဆက်ထားပါက ပြန်လည်ကျပန်းပြုလုပ်မည် မဟုတ်ပါ။"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ဤမုဒ်ကို ဖွင့်ထားသည့်အခါ MAC ကျပန်းပြုလုပ်ထားသည့် ကွန်ရက်သို့ ချိတ်ဆက်လိုက်သည့်အခါတိုင်း ဤစက်၏ MAC လိပ်စာ ပြောင်းသွားပါမည်။"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"အခမဲ့ မဟုတ်ပါ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"အခမဲ့"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"မှတ်တမ်းကြားခံနယ် အရွယ်အစားများ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"နောက်ခံ အက်ပ်များအတွက် \'အက်ပ်တုံ့ပြန်မှုမရှိ\' ဟု ပြရန်"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ချန်နယ်သတိပေးချက်များပြပါ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ချန်နယ်မရှိဘဲ အကြောင်းကြားလျှင် စကရင်တွင်သတိပေးသည်"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ဖြတ်လမ်းလင့်ခ် သုံးရန်"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"အချိန်ကြာမျှဝေသော ဖြတ်လမ်းလင့်ခ် သုံးရန် လိုအပ်သည်"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ပြင်ပစက်တွင် အက်ပ်များခွင့်ပြုရန်"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"တိကျစွာ သတ်မှတ်ထားသည့်တန်ဖိုးများရှိသော်လည်း၊ ပြင်ပသိုလှောင်ခန်းများသို့ မည်သည့်အက်ပ်ကိုမဆို ဝင်ရောက်ခွင့်ပြုပါ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"လုပ်ဆောင်ချက်များ အရွယ်ပြောင်းနိုင်ခြင်း"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index e374d65..8dfa9a1 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis alternativer for sertifisering av trådløs skjerm"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduserer batteriforbruket og forbedrer nettverksytelsen"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Denne av/på-bryteren påvirker bare atferden til MAC-tilfeldiggjøring for klientmodus.\nNår denne modusen er aktivert, kan nettverk som har tilfeldig valgt MAC, få MAC-adressen tilfeldig valgt på nytt under tilknytning, avhengig av når klienten sist ble koblet fra nettverket. Ny tilfeldiggjøring oppstår ikke hvis enheten kobler seg til igjen innen fire timer."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Når denne modusen er slått på, kan MAC-adressen til denne enheten endres hver gang den kobler seg til et nettverk som har tilfeldiggjøring av MAC-adresse slått på."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Med datamåling"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Uten datamåling"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Bufferstørrelser for logg"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Vis Appen svarer ikke-dialog for bakgrunnsapper"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Vis varselskanaladvarsler"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viser advarsler på skjermen når apper publiserer varsler uten en gyldig kanal"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Håndhev snarveier for samtalevarsler"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Krev at varsler støttes av en langvarig delingssnarvei for å vises i samtaledelen"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Tving frem tillatelse for ekstern lagring av apper"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Dette gjør at alle apper kan lagres på eksterne lagringsmedier – uavhengig av manifestverdier"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Tving aktiviteter til å kunne endre størrelse"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 870a6d1..42ef162 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ब्याट्रीको खपत कम गरी नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"यो टगलले क्लाइन्ट मोडमा मात्र MAC ठेगाना बदल्ने सुविधामा असर पार्न सक्छ।\nयो मोड सक्रिय हुँदा MAC बदल्ने सुविधा सक्षम पारेको कुनै पनि नेटवर्कको MAC ठेगाना पुनः बदल्न सकिन्छ। यसका लागि नेटवर्क कनेक्ट भएको हुनु पर्छ। यो कुरा क्लाइन्टले उक्त नेटवर्क पछिल्लो पटक कहिले डिस्कनेक्ट गरेको थियो भन्ने कुरामा पनि भर पर्छ। यन्त्र ४ घन्टा वा सोभन्दा कम समयमा फेरि कनेक्ट हुन्छ भने MAC ठेगाना पुनः बदलिँदैन।"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"यो मोड अन गरिएका बेला यो यन्त्र MAC ठेगाना बदल्ने सुविधा अन गरिएको कुनै इन्टरनेटसँग जति पटक कनेक्ट हुन्छ त्यति नै पटक यस यन्त्रको MAC ठेगाना पनि परिवर्तन हुन सक्छ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"मिटर नगरिएको"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"लगर बफर आकारहरू"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"पृष्ठभूमिका एपहरूको संवादको प्रतिक्रिया नदिइरहेका एपहरू प्रदर्शन गर्नुहोस्"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना च्यानलका चेतावनी देखाउनुहोस्"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"अनुप्रयोगले कुनै मान्य च्यानल बिना सूचना पोस्ट गर्दा स्क्रिनमा चेतावनी देखाउँछ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"कुराकानी नामक स्थानमा मान्य सर्टकटसँग पनि लिंक गरिएका सूचनाहरू मात्र देखाइयोस्"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"कुराकानी नामक स्थानमा सूचनाहरू देखिन सकून् भन्नाका खातिर ती सूचनामा सधैँ सक्रिय रहने (long-lived) सेयरिङ सर्टकट समावेश भएको हुनु पर्छ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"बाह्यमा बल प्रयोगको अनुमति प्राप्त एपहरू"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"म्यानिफेेस्टका मानहरूको ख्याल नगरी कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न सकिने खाले बनाउँछ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"आकार बदल्न योग्य हुने बनाउन गतिविधिहरूलाई बाध्यात्मक बनाउनुहोस्।"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथि"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index d034b49..6391690 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaagt het batterijverbruik en verbetert de netwerkprestaties"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Deze schakelaar beïnvloedt het gedrag van MAC-herschikking uitsluitend voor de clientmodus.\nAls deze modus is ingeschakeld, worden de MAC-adressen van netwerken die MAC-herschikking hebben ingeschakeld, mogelijk opnieuw in willekeurige volgorde herschikt als verbinding wordt gemaakt. Dit is afhankelijk van wanneer de client voor het laatst de verbinding met het netwerk verbrak. Opnieuw herschikken gebeurt niet als het apparaat binnen vier uur opnieuw verbinding maakt."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Als deze modus is ingeschakeld, kan het MAC-adres van dit apparaat elke keer wijzigen als het verbinding maakt met een netwerk waarvoor MAC-herschikking is ingeschakeld."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Met datalimiet"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Gratis"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-buffergrootten"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Dialoogvenster \'App reageert niet\' weergeven voor achtergrond-apps"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kanaalwaarschuwingen voor meldingen weergeven"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Geeft een waarschuwing op het scherm weer wanneer een app een melding post zonder geldig kanaal"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Snelkoppelingen voor gespreksmeldingen afdwingen"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vereisen dat meldingen een langdurige snelkoppeling voor delen krijgen om bij gesprekken te kunnen worden getoond"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Toestaan van apps op externe opslag afdwingen"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hiermee komt elke app in aanmerking voor schrijven naar externe opslag, ongeacht de manifestwaarden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Apparaatstandaard"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Uitgeschakeld"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 4341845..aea13b5c 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"ଅଜଣା"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ଉପଯୋଗକର୍ତ୍ତା: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"କିଛି ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ ମାନ ସେଟ୍ ହୋଇଛି"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"କୌଣସି ପୂର୍ବ-ନିର୍ଦ୍ଧାରଣ ସେଟ୍ ହୋଇନାହିଁ"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"କୌଣସି ଡିଫଲ୍ଟ ସେଟ୍ ହୋଇନାହିଁ"</string>
<string name="tts_settings" msgid="8130616705989351312">"ଟେକ୍ସଟ-ରୁ-ସ୍ପିଚ୍ ସେଟିଂସ୍"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ଟେକ୍ସଟ-ରୁ-ସ୍ପିଚ୍ ଆଉଟପୁଟ୍"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"ସ୍ପିଚ୍ ରେଟ୍"</string>
@@ -203,9 +203,9 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନୁହେଁ"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଙ୍ଗ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ନାମର ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗ୍ ହେଉଛି"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗିଂ"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍ ମୋଡ୍"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଙ୍ଗ ଅଧିକାରକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଂ ଅଧିକାରକୁ ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"ୱାୟାରଲେସ୍ ଡିବଗିଂ"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"ୱାଇ-ଫାଇ ସଂଯୁକ୍ତ ଥିବା ବେଳେ ଡିବଗ୍ ମୋଡ୍"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"ତ୍ରୁଟି"</string>
@@ -222,7 +222,7 @@
<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">"ୱାଇ-ଫାଇ ପେୟାରିଂ କୋଡ୍"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"ପେୟାରିଂ ବିଫଳ ହେଲା"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"ଡିଭାଇସଟି ସମାନ ନେଟୱାର୍କରେ ସଂଯୋଗ ହୋଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ୱେୟାରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ଏହି ଟୋଗଲ୍ କେବଳ କ୍ଲାଏଣ୍ଟ ମୋଡ୍ ପାଇଁ MAC ରେଣ୍ଡମାଇଜେସନ୍ ବ୍ୟବହାରକୁ ପ୍ରଭାବିତ କରେ।\nଯେତେବେଳେ ଏହି ମୋଡକୁ ସକ୍ରିୟ କରାଯାଏ, ସେତେବେଳେ କ୍ଲାଏଣ୍ଟ ଗତଥର କେତେବେଳେ ନେଟୱାର୍କରୁ ସଂଯୋଗ ବିଚ୍ଛିନ୍ନ କରିଥିଲେ ତାହା ଉପରେ ନିର୍ଭର କରି, MAC ରେଣ୍ଡମାଇଜେସନ୍ ସକ୍ଷମ କରାଯାଇଥିବା ଯେ କୌଣସି ନେଟୱାର୍କର MAC ଠିକଣାଗୁଡ଼ିକୁ ସଂଯୋଜନ ସମୟରେ ପୁଣି ରେଣ୍ଡମାଇଜ୍ କରାଯାଇପାରେ। ଯଦି ଡିଭାଇସଟି 4 ଘଣ୍ଟା କିମ୍ବା ତାଠାରୁ କମ୍ ସମୟରେ ପୁଣି ସଂଯୋଗ କରେ, ତେବେ ପୁଣି ରେଣ୍ଡମାଇଜେସନ୍ ହୁଏ ନାହିଁ।"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ଯେତେବେଳେ ଏହି ମୋଡ୍ ସକ୍ଷମ ହୁଏ, ପ୍ରତ୍ୟେକ ଥର MAC ରେଣ୍ଡୋମାଇଜେସନ୍ ସକ୍ଷମ ଥିବା କୌଣସି ନେଟୱାର୍କ ସହ ଏହି ଡିଭାଇସ୍ ସଂଯୋଗ ହେଲେ ଏହାର MAC ଠିକଣା ବଦଳିପାରେ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ମପାଯାଉଥିବା"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ମପାଯାଉନଥିବା"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ଲଗର୍ ବଫର୍ ସାଇଜ୍"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ \"ଆପ୍ ଉତ୍ତର ଦେଉନାହିଁ\" ଡାୟଲଗ୍ ଦେଖାନ୍ତୁ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ବିଜ୍ଞପ୍ତି ଚେନାଲ୍ ଚେତାବନୀ ଦେଖାନ୍ତୁ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ବୈଧ ଚ୍ୟାନେଲ୍ ବିନା ଗୋଟିଏ ଆପ୍ ଏକ ବିଜ୍ଞପ୍ତି ପୋଷ୍ଟ କରିବାବେଳେ ଅନ୍-ସ୍କ୍ରୀନ୍ ସତର୍କତା ଦେଖାଏ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତି ପାଇଁ ସର୍ଟକଟ ଲାଗୁ କରନ୍ତୁ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ବାର୍ତ୍ତାଳାପ ବିଭାଗରେ ଦେଖାଯିବା ପାଇଁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଏକ ଦୀର୍ଘ-ସ୍ଥାୟୀ ସେୟାରିଂ ସର୍ଟକଟର ସମର୍ଥନ ଆବଶ୍ୟକ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ଆପ୍କୁ ଏକ୍ସଟର୍ନଲ୍ ମେମୋରୀରେ ଫୋର୍ସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ଯେକୌଣସି ଆପ୍କୁ ଏକ୍ସଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍ରେ ଲେଖାଯୋଗ୍ୟ କରନ୍ତୁ, ମେନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ୱିଣ୍ଡୋ ହିସାବରେ କାର୍ଯ୍ୟକଳାପର ଆକାର ବଦଳାନ୍ତୁ"</string>
@@ -497,7 +495,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"କମ୍ ସମୟ।"</string>
<string name="cancel" msgid="5665114069455378395">"କ୍ୟାନ୍ସଲ୍"</string>
<string name="okay" msgid="949938843324579502">"ଠିକ୍ ଅଛି"</string>
- <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରନ୍ତୁ"</string>
<string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"କଦାପି ନୁହେଁ"</string>
<string name="zen_interruption_level_priority" msgid="5392140786447823299">"କେବଳ ପ୍ରାଥମିକତା"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ଅତିଥି"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index b47b5fb..b502f3f 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"ਅਗਿਆਤ"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"ਵਰਤੋਂਕਾਰ: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"ਕੁਝ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈੱਟ ਕੀਤੇ"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"ਕੋਈ ਡਿਫੌਲਟਸ ਸੈਟ ਨਹੀਂ ਕੀਤੇ"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"ਕੋਈ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈੱਟ ਨਹੀਂ ਕੀਤੇ"</string>
<string name="tts_settings" msgid="8130616705989351312">"ਲਿਖਤ ਤੋਂ ਬੋਲੀ ਸੈਟਿੰਗਾਂ"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"ਲਿਖਤ ਤੋਂ ਬੋਲੀ ਆਊਟਪੁੱਟ"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"ਬੋਲਣ ਦੀ ਗਤੀ"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਘਟਾ ਕੇ ਨੈੱਟਵਰਕ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਂਦਾ ਹੈ"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ਇਹ ਟੌਗਲ ਸਿਰਫ਼ ਕਲਾਇੰਟ ਮੋਡ ਲਈ MAC ਦੇ ਬੇਤਰਤੀਬਵਾਰ ਵਿਵਹਾਰ \'ਤੇ ਅਸਰ ਪਾਉਂਦਾ ਹੈ।\nਜਦੋਂ ਇਸ ਮੋਡ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਜਿਹੜੇ ਵੀ ਨੈੱਟਵਰਕਾਂ ਵਿੱਚ MAC ਬੇਤਰਤੀਬਵਾਰ ਚਾਲੂ ਹੈ ਉਹਨਾਂ ਦੇ MAC ਪਤਿਆਂ ਦਾ ਸਾਂਝੇਦਾਰੀ ਦੌਰਾਨ ਮੁੜ-ਬੇਤਰਤੀਬੀਕਰਨ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ, ਜੋ ਕਲਾਇੰਟ ਦੇ ਪਿਛਲੀ ਵਾਰ ਨੈੱਟਵਰਕ ਤੋਂ ਡਿਸਕਨੈਕਟ ਹੋਣ \'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ। ਜੇ ਡੀਵਾਈਸ 4 ਘੰਟੇ ਜਾਂ ਘੱਟ ਸਮੇਂ ਵਿੱਚ ਮੁੜ-ਕਨੈਕਟ ਹੋ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਮੁੜ-ਬੇਤਰਤੀਬਵਾਰ ਨਹੀਂ ਹੋਵੇਗਾ।"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ਜਦੋਂ ਇਹ ਮੋਡ ਚਾਲੂ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਇਸ ਡੀਵਾਈਸ ਦਾ MAC ਪਤਾ ਹਰ ਵਾਰ ਬਦਲ ਸਕਦਾ ਹੈ ਜਦੋਂ ਇਹ ਕਿਸੇ ਅਜਿਹੇ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ MAC ਦਾ ਬੇਤਰਤੀਬੀਕਰਨ ਚਾਲੂ ਹੁੰਦਾ ਹੈ।"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ਗੈਰ-ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ਲੌਗਰ ਬਫ਼ਰ ਆਕਾਰ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"ਬੈਕਗ੍ਰਾਊਂਡ ਐਪਾਂ ਲਈ \'ਐਪ ਪ੍ਰਤਿਕਿਰਿਆ ਨਹੀਂ ਦੇ ਰਹੀ ਹੈ\' ਵਿੰਡੋ ਦਿਖਾਓ"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ਸੂਚਨਾ ਚੈਨਲ ਚਿਤਾਵਨੀਆਂ ਦਿਖਾਓ"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ਐਪ ਵੱਲੋਂ ਵੈਧ ਚੈਨਲ ਤੋਂ ਬਿਨਾਂ ਸੂਚਨਾ ਪੋਸਟ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਚਿਤਾਵਨੀ ਦਿਖਾਉਂਦੀ ਹੈ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਸੂਚਨਾਵਾਂ ਲਈ ਸ਼ਾਰਟਕੱਟ ਲਾਗੂ ਕਰੋ"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਦਿਸਣ ਲਈ ਚਿਰਸਥਾਈ ਸਾਂਝਾਕਰਨ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਸੂਚਨਾਵਾਂ ਦਾ ਬੈਕਅੱਪ ਲੈਣਾ ਲੋੜੀਂਦਾ ਹੈ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ਐਪਾਂ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਆਗਿਆ ਦਿਓ"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਕਿਸੇ ਵੀ ਐਪ ਨੂੰ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ਮਹਿਮਾਨ"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index cc0543e..cdcb651 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Wybierz profil"</string>
<string name="category_personal" msgid="6236798763159385225">"Osobiste"</string>
- <string name="category_work" msgid="4014193632325996115">"Służbowe"</string>
+ <string name="category_work" msgid="4014193632325996115">"Do pracy"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opcje programistyczne"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Włącz opcje dla programistów"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Ustaw opcje związane z programowaniem aplikacji."</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmniejsza zużycie baterii i zwiększa wydajność sieci"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ten przełącznik wpływa na zachowanie randomizacji MAC tylko w przypadku trybu klienta.\nKiedy ten tryb jest aktywny, adresy MAC dowolnej sieci, która ma włączoną randomizację MAC, podczas powiązywania mogą zostać poddane ponownej randomizacji, w zależności od tego, kiedy klient ostatni raz rozłączył się z siecią. Ponowna randomizacja nie zachodzi, jeśli urządzenie połączy się ponownie w ciągu 4 lub mniejszej liczby godzin."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kiedy ten tryb jest włączony, to adres MAC tego urządzenia może zmieniać się za każdym razem, kiedy urządzenie połączy się z siecią, która ma włączoną opcję randomizacji MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Użycie danych jest mierzone"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Użycie danych nie jest mierzone"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Rozmiary bufora rejestratora"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Wyświetlaj okno Aplikacja nie odpowiada dla aplikacji w tle"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Pokaż ostrzeżenia kanału powiadomień"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Wyświetla ostrzeżenie, gdy aplikacja publikuje powiadomienie bez prawidłowego kanału"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Wymuszaj skróty do powiadomień o rozmowie"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Wymagaj używania długoterminowych skrótów do udostępniania powiadomień, które pojawiałyby się w sekcji rozmowy"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Wymuś zezwalanie na aplikacje w pamięci zewnętrznej"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Pozwala na zapis aplikacji w pamięci zewnętrznej niezależnie od wartości w pliku manifestu"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Wymuś zmianę rozmiaru okien aktywności"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 99fa609..d685802 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -223,7 +223,7 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Falha na conexão"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Verifique se o <xliff:g id="DEVICE_NAME">%1$s</xliff:g> está conectado à rede correta"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Parear com o dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Essa opção afeta o comportamento de ordem aleatória de MAC somente para o modo cliente.\nQuando esse modo é ativado, todas as redes que tiverem a ordem aleatória de MAC ativada poderão ter a ordem aleatória refeita durante a associação, dependendo de quando o cliente se desconectou da rede pela última vez. A ordem aleatória não será refeita se o dispositivo se reconectar em até quatro horas."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando esse modo está ativado, o endereço MAC do dispositivo pode mudar a cada vez que ele se conecta a uma rede com ordem aleatória de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificações"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atalhos para notificações de conversa"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que as notificações sejam apoiadas por um atalho de compartilhamento de longa duração para que elas possam aparecer na seção de conversa"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Padrão do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 6318c6d..ca808b9 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções da certificação de display sem fios"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo rápido da bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Este botão ativar/desativar afeta o comportamento da seleção aleatória do MAC apenas para o modo de cliente.\nQuando este modo está ativado, qualquer rede que tenha a seleção aleatória do MAC ativa pode fazer com que os seus endereços MAC sejam novamente selecionados de forma aleatória durante a associação, dependendo de quando o cliente se desligou da rede pela última vez. A nova seleção aleatória não ocorre se a ligação do dispositivo for restabelecida em 4 horas ou menos."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando este modo estiver ativado, o endereço MAC deste dispositivo pode mudar sempre que o mesmo estabelece ligação a uma rede que tenha a seleção aleatória do MAC ativada."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Acesso limitado"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Acesso ilimitado"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos da memória intermédia do registo"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar caixa de diálogo A aplicação não está a responder para aplicações em segundo plano"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos do canal de notificações"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra um aviso no ecrã quando uma aplicação publica uma notificação sem o canal ser válido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Aplicar atalhos para notificações de conversas"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Solicitar cópia de seg. das notif. por atalho de partilha de longa duração p/ apresentação na secção de conversas"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps no armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Torna qualquer aplicação elegível para ser gravada no armazenamento externo, independentemente dos valores do manifesto"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar as atividades a serem redimensionáveis"</string>
@@ -401,7 +399,7 @@
<string name="inactive_apps_title" msgid="5372523625297212320">"Aplicações em espera"</string>
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Inativo. Toque para ativar/desativar."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Ativo. Toque para ativar/desativar."</string>
- <string name="standby_bucket_summary" msgid="5128193447550429600">"Estado do Modo de espera das aplicações:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
+ <string name="standby_bucket_summary" msgid="5128193447550429600">"Estado do Modo de espera das apps:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Predefinição do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativada"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 99fa609..d685802 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -223,7 +223,7 @@
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Falha na conexão"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Verifique se o <xliff:g id="DEVICE_NAME">%1$s</xliff:g> está conectado à rede correta"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Parear com o dispositivo"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento de Wi‑Fi"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Essa opção afeta o comportamento de ordem aleatória de MAC somente para o modo cliente.\nQuando esse modo é ativado, todas as redes que tiverem a ordem aleatória de MAC ativada poderão ter a ordem aleatória refeita durante a associação, dependendo de quando o cliente se desconectou da rede pela última vez. A ordem aleatória não será refeita se o dispositivo se reconectar em até quatro horas."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quando esse modo está ativado, o endereço MAC do dispositivo pode mudar a cada vez que ele se conecta a uma rede com ordem aleatória de MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificações"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atalhos para notificações de conversa"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que as notificações sejam apoiadas por um atalho de compartilhamento de longa duração para que elas possam aparecer na seção de conversa"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Padrão do dispositivo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f64cfbf..5954d74 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce descărcarea bateriei și îmbunătățește performanța rețelei"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Acest comutator influențează comportamentul de randomizare a adresei MAC numai pentru modul client.\nCând este activat acest mod, toate rețelele care au activată randomizarea adresei MAC pot randomiza din nou adresele MAC în timpul asocierii, în funcție de ora ultimei deconectări a clientului de la rețea. Randomizarea nu se repetă dacă dispozitivul se reconectează în decurs de 4 ore."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Când acest mod este activat, adresa MAC a dispozitivului se poate schimba de fiecare dată când se conectează la o rețea care are activată randomizarea MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Contorizată"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Necontorizată"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Dimensiunile memoriei temporare a jurnalului"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Afișați dialogul Aplicația nu răspunde pentru aplicațiile din fundal"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Afișați avertismentele de pe canalul de notificări"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afișați avertisment pe ecran când o aplicație postează o notificare fără canal valid"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Comenzi rapide pt. notif. de conversație"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Notificările trebuie susținute de o comandă rapidă veche de trimitere ca să apară în secțiunea conversației"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Forțați accesul aplicațiilor la stocarea externă"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Faceți ca orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forțați redimensionarea activităților"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 71c7cf3..22b8b25 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показывать параметры сертификации беспроводных мониторов"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Уменьшает расход заряда батареи и улучшает работу сети"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Эта настройка влияет на использование случайных MAC-адресов только в клиентском режиме.\nВо время подключения к любой сети происходит повторное создание случайного MAC-адреса в зависимости от того, когда клиент последний раз отключался от сети. Это не происходит, если соединение возобновляется через четыре часа или раньше."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Если этот режим активирован, MAC-адрес устройства может меняться при каждом подключении к сети, в которой возможно создание случайных MAC-адресов."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Сеть с тарификацией трафика"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Сеть без тарификации трафика"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Размер буфера журнала"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Уведомлять о том, что приложение, запущенное в фоновом режиме, не отвечает"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Показывать предупреждения канала передачи уведомлений"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Показывать предупреждение о новых уведомлениях приложения вне допустимого канала"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Принудительное использование ярлыков для уведомлений из чатов"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Обязательно дублировать уведомления с помощью долго отображаемых ярлыков, чтобы уведомления появлялись в разделе чатов"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Разрешить сохранение на внешние накопители"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Разрешить сохранение приложений на внешних накопителях (независимо от значений в манифесте)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Изменение размера в многооконном режиме"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index bbf40db..26677f7 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"බැටරි බැසීම අඩු කරන අතර ජාල කාර්ය සාධනය වැඩි දියුණු කරයි"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"මෙම ටොගලය සේවාලාභී ප්රකාරය සඳහා පමණක් MAC සසම්භාවීකරණ හැසිරීමට බලපායි.\nමෙම ප්රකාරය සක්රිය කර ඇති විට, MAC සසම්භාවීකරණය සබල කර ඇති ඕනෑම ජාලයකට, සේවාලාභියා අවසන් වරට ජාලයෙන් විසන්ධි වූයේ කවදාද යන්න මත පදනම්ව සම්බන්ධය අතරතුර ඔවුන්ගේ MAC ලිපින යළි සසම්භාවිකරණය කර තිබිය හැකිය. උපාංගය පැය 4කින් හෝ ඊට අඩු කාලයකදී නැවත සම්බන්ධ වන්නේ නම් යළි සසම්භාවිකරණය සිදු නොවේ."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"මෙම ප්රකාරය අබල කළ විට, මෙම උපාංගයේ MAC ලිපිනය එය MAC සසම්භාවීකරණය සබල කර ඇති ජාලයකට සම්බන්ධවන ඒ ඒ අවස්ථාවල වෙනස් විය හැකිය."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"මනිනු ලැබේ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"මනින්නේ නැත"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ලෝගයේ අන්තරාවක ප්රමාණය"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"පසුබිම් යෙදුම්වලට යෙදුම ප්රතිචාර නොදක්වයි කවුළුව සංදර්ශනය කරන්න"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"දැනුම්දීම් නාලිකා අනතුරු ඇඟවීම් පෙන්."</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"යෙදුමක් වලංගු නාලිකාවකින් තොරව දැනුම්දීමක් පළ කරන විට තිරය-මත අනතුරු ඇඟවීමක් සංදර්ශනය කරයි."</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"සංවාද දැනුම් දීම් සඳහා කෙටිමං බලාත්මක කරන්න"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"සංවාද කොටසේ පෙනී සිටීම පිණිස දිගු කාලයක් පවතින බෙදා ගැනීමේ කෙටිමඟක් මඟින් දැනුම් දීම් අවහිර කිරීමට අවශ්ය වේ"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"බාහිර මත යෙදුම් ඉඩ දීම බල කරන්න"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් බාහිර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"ක්රියාකාරකම් ප්රතිප්රමාණ කළ හැකි බවට බල කරන්න"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
<string name="guest_nickname" msgid="6332276931583337261">"අමුත්තා"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index f988d46..53c2eb0 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -211,9 +211,9 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Chyba"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Bezdrôtové ladenie"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ak chcete zobraziť a používať dostupné zariadenia, zapnite bezdrôtové ladenie"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Spárovať zariadenie pomocou QR kódu"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Spárovať zariadenie QR kódom"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Spárujte nové zariadenia pomocou skenera QR kódov"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Spárovať zariadenie pomocou párovacieho kódu"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Spárovať zariadenie párovacím kódom"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Spárujte nové zariadenia pomocou šesťmiestneho kódu"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Spárované zariadenia"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Aktuálne pripojené"</string>
@@ -226,15 +226,15 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Párovací kód siete Wi-Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Párovanie zlyhalo"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Skontrolujte, či je zariadenie pripojené k rovnakej sieti."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Spárujte zariadenie cez Wi-Fi naskenovaním QR kódu"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Páruje sa zariadenie…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Zariadenie sa nepodarilo spárovať. Buď bol QR kód nesprávny, alebo zariadenie nie je pripojené k rovnakej sieti."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa IP a port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Naskenujte QR kód"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Spárujte zariadenie cez Wi-Fi naskenovaním QR kódu"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Pripojte sa k sieti Wi‑Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ladenie, dev"</string>
- <string name="bugreport_in_power" msgid="8664089072534638709">"Skratka hlásenia chyby"</string>
+ <string name="bugreport_in_power" msgid="8664089072534638709">"Odkaz na hlásenie chyby"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"Zobraziť v hlavnej ponuke tlačidlo na vytvorenie hlásenia chyby"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"Nevypínať obrazovku"</string>
<string name="keep_screen_on_summary" msgid="1510731514101925829">"Obrazovka sa pri nabíjaní neprepne do režimu spánku"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Znižuje používanie batérie a zlepšuje výkon siete"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Tento prepínač ovplyvňuje správanie randomizácie adresy MAC len pre režim klienta.\nKeď je tento režim aktivovaný, všetky siete s povolenou randomizáciou adresy MAC môžu mať svoje adresy MAC počas spájania opätovne randomizované v závislosti od toho, kedy sa klient od siete naposledy odpojil. Opätovná randomizácia nenastane, ak sa zariadenie znova pripojí do štyroch hodín."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Keď je tento režim aktivovaný, adresa MAC tohto zariadenia sa môže pri každom pripojení k sieti s aktivovanou randomizáciou adries MAC zmeniť."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Merané"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez merania dát"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávacia pamäť nástroja denníkov"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Zobrazovať dialógové okno „Aplikácia nereaguje“ pre aplikácie na pozadí"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Zobraziť hlásenia kanála upozornení"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Zobrazuje varovné hlásenie na obrazovke, keď aplikácia zverejní upozornenie bez platného kanála"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Vynútiť skratky pre upozornenia na konverzácie"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vyžadovať zastúpenie upozornení dlhodobou skratkou na zdieľanie, aby sa zobrazili v sekcii konverzácie"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Vynútiť povolenie aplikácií na externom úložisku"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index eb2077c..38ca86a 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -72,14 +72,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Povezano (brez predstavnosti) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Povezano (brez dostopa do sporočil) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Povezano (brez telefona/predstavnosti) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Povezano, raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Povezano (brez telefona), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Povezano (brez predstavnosti), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Povezano (brez telefona ali predstavnosti), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivna, akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Povezano, raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Povezano (brez telefona), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Povezano (brez predstavnosti), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Povezano (brez telefona ali predstavnosti), raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivna, baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvok predstavnosti"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski klici"</string>
@@ -129,8 +129,8 @@
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Seznanjanje z levim slušnim pripomočkom …"</string>
<string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Seznanjanje z desnim slušnim pripomočkom …"</string>
- <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Levi – akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Desni – akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Levi – baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Desni – baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi je izklopljen."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Povezava Wi-Fi je prekinjena."</string>
<string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Ena črtica signala Wi-Fi."</string>
@@ -283,8 +283,8 @@
<string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Povezave ni bilo mogoče vzpostaviti"</string>
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
- <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije akumulatorja in izboljša delovanje omrežja"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"To stikalo vpliva na dodeljevanje naključnega naslova MAC samo v načinu odjemalca.\nKo je ta način aktiviran, se omrežjem, pri katerih je omogočeno naključno dodeljevanje naslova MAC, med povezovanjem morda dodeli nov naključen naslov MAC, kar je odvisno od tega, kdaj je odjemalec nazadnje prekinil povezavo z omrežjem. Dodelitev novega naključnega naslova se ne izvede, če naprava znova vzpostavi povezavo po največ štirih urah."</string>
+ <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije baterije in izboljša delovanje omrežja"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Ko je ta način omogočen, se lahko naslov MAC te naprave spremeni vsakič, ko se naprava poveže v omrežje z omogočenim naključnim dodeljevanjem naslova MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Omejen prenos podatkov"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Z neomejenim prenosom podatkov"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Velikosti medpomnilnikov zapisovalnika dnevnika"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaz pogovornega okna za neodzivanje aplikacij v ozadju"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Pokaži opozorila kanala za obvestila"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Na zaslonu se pokaže opozorilo, ko aplikacija objavi obvestilo brez veljavnega kanala"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Uveljavitev bližnjic za obvestila pogovora"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Zahteva, da obvestila podpira dolgotrajna bližnjica za deljenje, da se prikažejo v razdelku s pogovorom"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Vsili omogočanje aplikacij v zunanji shrambi"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Vsili spremembo velikosti za aktivnosti"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 685be99..17d2d50 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Shfaq opsionet për certifikimin e ekranit valor"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zvogëlon shkarkimin e baterisë dhe përmirëson cilësinë e funksionimit të rrjetit"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ky ndryshim ndikon te sjellja e renditjes së rastësishme të adresave MAC vetëm për modalitetin e klientit.\nKur aktivizohet ky modalitet, çdo rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC mund t\'i rirendisë adresat e veta MAC gjatë shoqërimit, në varësi të kohës kur është shkëputur klienti për herë të fundit nga rrjeti. Rirenditja e rastësishme nuk ndodh nëse pajisja lidhet brenda 4 orëve ose më pak."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kur ky modalitet është i aktivizuar, adresa MAC e kësaj pajisjeje mund të ndryshojë çdo herë që lidhet me një rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Me matje"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Pa matje"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Madhësitë e regjistruesit"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Shfaq raportet ANR (Aplikacioni nuk përgjigjet) për aplikacionet në sfond"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Shfaq paralajmërimet e kanalit të njoftimeve"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Shfaq paralajmërimin në ekran kur një aplikacion poston një njoftim pa një kanal të vlefshëm"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Zbato shkurtoret për njoftimet e bisedave"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kërko që informacionet të mbështeten nga një shkurtore ndarjeje afatgjatë që ato të shfaqen në seksionin e bashkëbisedimit"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Detyro lejimin në hapësirën e jashtme"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Parazgjedhja e pajisjes"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Joaktiv"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 9188a76..ca15c2d 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -143,11 +143,11 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Уклоњене апликације"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Уклоњене апликације и корисници"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Ажурирања система"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB Интернет повезивање"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB привезивање"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Преносни хотспот"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth привезивање"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Повезивање са интернетом"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Повезивање и преносни хотспот"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Привезивање"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Привезивање и преносни хотспот"</string>
<string name="managed_user_title" msgid="449081789742645723">"Све радне апликације"</string>
<string name="user_guest" msgid="6939192779649870792">"Гост"</string>
<string name="unknown" msgid="3544487229740637809">"Непознато"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Приказ опција за сертификацију бежичног екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Смањује потрошњу батерије и побољшава учинак мреже"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Овај прекидач утиче на понашање насумичног разврставања MAC адреса само за режим клијента.\nКада се овај режим активира, за мреже на којима је омогућено насумично разврставање MAC адреса може да дође до поновног насумичног разврставања MAC адреса током повезивања, у зависности од тога када се клијент пре тога искључио са мреже. До поновног насумичног разврставања не долази ако се уређај поново повеже за 4 сата или мање."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Када је овај режим омогућен, MAC адреса овог уређаја може да се промени сваки пут када се повеже са мрежом на којој је омогућено насумично разврставање MAC адреса."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Са ограничењем"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничења"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Величине бафера података у програму за евидентирање"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Прикажи дијалог Апликација не реагује за апликације у позадини"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Приказуј упозорења због канала за обавештења"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Приказује упозорење на екрану када апликација постави обавештење без важећег канала"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Примењуј пречице за обавештења о конверзацијама"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Захтева да обавештења имају и дугорочну пречицу за дељење како би се појављивала у одељку за конверзације"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Принудно дозволи апликације у спољној"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Принудно омогући промену величине активности"</string>
@@ -552,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index c383e577..ee48c2f 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sänker batteriförbrukningen och förbättrar nätverksprestandan"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Detta läge påverkar endast MAC-slumpgenereringens beteende för klientläget.\nNär läget aktiveras kan alla nätverk som har MAC-slumpgenerering aktiverat få sina adresser slumpgenererade på nytt under kopplingen, beroende på när klienten senast kopplade från nätverket. Det sker ingen ny slumpgenerering om enheten återansluter inom fyra timmar."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"När det här läget är aktiverat kan enhetens MAC-adress ändras varje gång den ansluts till ett nätverk där slumpgenerering av MAC-adress har aktiverats."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Med datapriser"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Utan datapriser"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Buffertstorlekar för logg"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Visa dialogrutan om att appen inte svarar för bakgrundsappar"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Visa varningar om aviseringskanal"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Visa varningar på skärmen när en app lägger upp en avisering utan en giltig kanal"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kräv genvägar för konversationsaviseringar"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kräv att aviseringar har en långlivad delningsgenväg för att få visas i konversationsavsnittet"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Tillåt appar i externt lagringsutrymme"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Allar appar kan skrivas till extern lagring, oavsett manifestvärden"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Framtvinga storleksanpassning för aktiviteter"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 25424b0..7df39d5 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -224,7 +224,7 @@
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Hakikisha kuwa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kimeunganishwa kwenye mtandao sahihi"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Oanisha na kifaa"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Msimbo wa kuoanisha wa Wi-Fi"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Imeshindwa kuunganisha"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Imeshindwa kuoanisha"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Hakikisha kuwa kifaa kimeunganishwa kwenye mtandao mmoja."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Oanisha kifaa kupitia Wi-Fi kwa kuchanganua msimbo wa QR"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Inaoanisha kifaa…"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Hupunguza matumizi ya chaji ya betri na kuboresha utendaji wa mtandao"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hali hii ya kugeuza huathiri utendaji wa kuweka nasibu kwenye anwani ya MAC katika hali ya kiteja pekee.\nWakati hali hii imewashwa, mitandao yoyote ambapo kipengele cha unasibu wa MAC kimewashwa inaweza kuruhusu anwani zao za MAC kuwekwa nasibu tena wakati wa ushirikiano, kulingana na mara ya mwisho kiteja kilipoacha kuunganisha kwenye mtandao. Tukio la kuweka unasibu tena halitokei ikiwa kifaa kitaunganisha tena baada ya muda usiozidi saa nne."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wakati hali hii imewashwa, huenda anwani ya MAC ya kifaa hiki ikabadilika kila wakati kinapounganisha kwenye mtandao ambapo kipengele cha unasibu wa MAC kimewashwa."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Mtandao unapima data"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Mtandao usiopima data"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Ukubwa wa kiweka bafa ya kumbukumbu"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Onyesha kidirisha cha Programu Kutorejesha Majibu kwa programu zinazotumika chinichini"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Onyesha arifa za maonyo ya kituo"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Huonyesha onyo kwenye skrini programu inapochapisha arifa bila kituo sahihi."</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Tekeleza njia za mkato za arifa za mazungumzo"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Weka mipangilio ili nakala za arifa zihifadhiwe kwa njia ya zamani ya mkato ya kushiriki ili zionekane katika sehemu ya mazungumzo"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Lazima uruhusu programu kwenye hifadhi ya nje"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Huruhusu programu yoyote iwekwe kwenye hifadhi ya nje, bila kujali thamani za faili ya maelezo"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Hali chaguomsingi ya kifaa"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index a57fd0e..eb7fc05 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -284,7 +284,8 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"கிளையண்ட் பயன்முறைக்கான MAC ரேண்டம் ஆக்குதலை மட்டுமே இந்த நிலைமாற்றி பாதிக்கும்.\nஇந்தப் பயன்முறை இயக்கப்பட்டால் நெட்வொர்க்கிலிருந்து கிளையண்ட் கடைசியாக எப்போது துண்டிக்கப்பட்டது என்பதைப் பொறுத்து, MAC ரேண்டம் ஆக்குதல் இயக்கப்பட்டிருக்கும் நெட்வொர்க்குகள் இணைக்கப்படும்போது தங்கள் MAC முகவரிகளை மீண்டும் ரேண்டம் ஆக்கக்கூடும். சாதனம் 4 மணிநேரத்திலோ அதற்கு முன்னரோ மீண்டும் இணைக்கப்பட்டால் மீண்டும் ரேண்டம் ஆக்குதல் நிகழாது."</string>
+ <!-- no translation found for wifi_enhanced_mac_randomization_summary (1210663439867489931) -->
+ <skip />
<string name="wifi_metered_label" msgid="8737187690304098638">"கட்டண நெட்வொர்க்"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"கட்டணமில்லா நெட்வொர்க்"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"லாகர் பஃபர் அளவுகள்"</string>
@@ -373,8 +374,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"பின்புல ஆப்ஸுக்கு, ஆப்ஸ் பதிலளிக்கவில்லை என்ற செய்தியைக் காட்டும்"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"அறிவிப்புச் சேனல் எச்சரிக்கைகளைக் காட்டு"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ஆப்ஸானது சரியான சேனல் இல்லாமல் அறிவிப்பை இடுகையிடும் போது, திரையில் எச்சரிக்கையைக் காட்டும்"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"உரையாடல் அறிவிப்புகளுக்கான ஷார்ட்கட்களை செயல்படுத்து"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"அறிவிப்புகளானது உரையாடல் பிரிவில் தோன்ற வேண்டும் எனில் அவை நீண்ட காலம் செயல்பாட்டில் இருந்த பகிர்தலுக்கான ஷார்ட்கட் ஆதரவைக் கொண்டிருக்க வேண்டும்"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"ஆப்ஸை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா ஆப்ஸையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
@@ -551,4 +550,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
<string name="guest_nickname" msgid="6332276931583337261">"கெஸ்ட்"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index b618610..0e36c5f 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -153,7 +153,7 @@
<string name="unknown" msgid="3544487229740637809">"తెలియదు"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"వినియోగదారు: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని డిఫాల్ట్లు సెట్ చేయబడ్డాయి"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"డిఫాల్ట్లు ఏవీ సెట్ చేయబడలేదు"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"ఆటోమేటిక్ ఆప్షన్లు వేటినీ సెట్ చేయలేదు"</string>
<string name="tts_settings" msgid="8130616705989351312">"వచనం నుండి ప్రసంగం సెట్టింగ్లు"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"వచనం నుండి మాట అవుట్పుట్"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"ప్రసంగం రేట్"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి & నెట్వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"క్లయింట్ మోడ్లో మాత్రమే MAC ర్యాండమైజేషన్ ప్రవర్తనను ఈ టోగుల్ ప్రభావితం చేస్తుంది.\nఈ మోడ్ను యాక్టివేట్ చేసినప్పుడు, క్లయింట్ చివరిసారిగా నెట్వర్క్ నుండి ఎప్పుడు డిస్కనెక్ట్ చేసారనే దానిని బట్టి, అనుబంధం జరిగేటప్పుడు MAC ర్యాండమైజేషన్ ఎనేబుల్ చేయబడిన ఏ నెట్వర్క్లు అయినా వాటి MAC చిరునామాలను తిరిగి ర్యాండమైజేషన్ చేయవచ్చు. పరికరం 4 గంటలు లేదా అంతకన్నా తక్కువ సమయంలో మళ్లీ కనెక్ట్ చేయబడితే తిరిగి ర్యాండమైజేషన్ చేయడమనేది జరగదు."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్ను ఎనేబుల్ చేసిన నెట్వర్క్తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్ మారవచ్చు."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"గణించబడుతోంది"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"గణించబడటం లేదు"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"లాగర్ బఫర్ పరిమాణాలు"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"నేపథ్య యాప్ల కోసం యాప్ ప్రతిస్పందించడం లేదు అనే డైలాగ్ను చూపు"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"ఛానెల్ హెచ్చరికల నోటిఫికేషన్ను చూపు"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"చెల్లుబాటు అయ్యే ఛానెల్ లేకుండా యాప్ నోటిఫికేషన్ను పోస్ట్ చేస్తున్నప్పుడు స్క్రీన్పై హెచ్చరికను చూపిస్తుంది"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"సంభాషణ నోటిఫికేషన్లకు షార్ట్కట్ల అమలు"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"సంభాషణల విభాగంలో కనిపించడానికి చిరకాలం నిలిచిపోయే భాగస్వామ్య సత్వరమార్గం ద్వారా నోటిఫికేషన్లకు మద్దతు ఉండాలి."</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"యాప్లను బాహ్య నిల్వలో తప్పనిసరిగా అనుమతించు"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"ఏ యాప్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో సేవ్ చేయడానికి అనుమతిస్తుంది"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"కార్యకలాపాల విండోల పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string>
<string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 315fab9..b4e1eea 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -205,7 +205,7 @@
<string name="apn_settings_not_available" msgid="1147111671403342300">"การตั้งค่าจุดเข้าใช้งานไม่สามารถใช้ได้สำหรับผู้ใช้รายนี้"</string>
<string name="enable_adb" msgid="8072776357237289039">"การแก้ไขข้อบกพร่อง USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"โหมดแก้ไขข้อบกพร่องเมื่อเชื่อมต่อ USB"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"ยกเลิกการให้สิทธิ์การแก้ปัญหา USB"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"เพิกถอนการให้สิทธิ์การแก้ไขข้อบกพร่อง USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"การแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"โหมดแก้ไขข้อบกพร่องเมื่อเชื่อมต่อ Wi-Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"ข้อผิดพลาด"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"การตั้งค่านี้ส่งผลต่อลักษณะการสุ่ม MAC ในโหมดไคลเอ็นต์เท่านั้น\nเมื่อเปิดใช้งานโหมดนี้ ทุกเครือข่ายที่มีการเปิดใช้การสุ่ม MAC อาจสุ่มที่อยู่ MAC ซ้ำในระหว่างการเชื่อมโยง ทั้งนี้ขึ้นอยู่กับว่าไคลเอ็นต์ยกเลิกการเชื่อมต่อกับเครือข่ายครั้งสุดท้ายเมื่อใด การสุ่มซ้ำจะไม่เกิดขึ้นหากอุปกรณ์เชื่อมต่ออีกครั้งภายในไม่เกิน 4 ชั่วโมง"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์นี้อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายที่มีการเปิดใช้การสุ่ม MAC"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
@@ -359,7 +359,7 @@
<string name="track_frame_time" msgid="522674651937771106">"การแสดงผล HWUI ตามโปรไฟล์"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"เปิดใช้เลเยอร์การแก้ไขข้อบกพร่อง GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"อนุญาตให้โหลดเลเยอร์การแก้ไขข้อบกพร่อง GPU สำหรับแอปแก้ไขข้อบกพร่อง"</string>
- <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"เปิดบันทึกเวนเดอร์เพิ่มเติม"</string>
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"เปิดการบันทึกเวนเดอร์แบบละเอียด"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"รวมบันทึกเวนเดอร์เพิ่มเติมเฉพาะอุปกรณ์ไว้ในรายงานข้อบกพร่อง ซึ่งอาจมีข้อมูลส่วนตัว ใช้แบตเตอรี่มากขึ้น และ/หรือใช้พื้นที่เก็บข้อมูลมากขึ้น"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"อัตราการเคลื่อนไหวของหน้าต่าง"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"อัตราการเคลื่อนไหวของการเปลี่ยนภาพ"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"แสดงกล่องโต้ตอบ \"แอปไม่ตอบสนอง\" สำหรับแอปพื้นหลัง"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"แสดงคำเตือนจากช่องทางการแจ้งเตือน"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"แสดงคำเตือนบนหน้าจอเมื่อแอปโพสต์การแจ้งเตือนโดยไม่มีช่องทางที่ถูกต้อง"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"บังคับใช้ทางลัดสำหรับการแจ้งเตือนการสนทนา"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ต้องทำให้การแจ้งเตือนปรากฏในส่วนการสนทนาได้อีกถ้ามีการปิดไปโดยใช้ทางลัดการแชร์ที่แสดงอยู่ตลอด"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"เขียนแอปในพื้นที่เก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าไฟล์ Manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"บังคับให้กิจกรรมปรับขนาดได้"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 2ea03a4..22ad220 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Binabawasan ang pagkaubos ng baterya at pinapahusay ang performance ng network"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Nakakaapekto ang toggle na ito sa pag-kilos ng pag-randomize ng MAC para lang sa client mode.\nKapag na-activate ang mode na ito, baka ma-randomize ulit ang MAC address ng anumang network na naka-enable ang pag-randomize sa MAC habang nagaganap ang pag-uugnay, depende kung kailan huling nadiskonekta ang client sa network. Hindi nangyayari ang pag-randomize ulit kung kumonekta ulit ang device sa loob ng 4 na oras o mas maaga."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Kapag naka-enable ang mode na ito, puwedeng magbago ang MAC address ng device na ito sa tuwing kokonekta ito sa isang network na may naka-enable na MAC randomization."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Nakametro"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Hindi Nakametro"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Mga laki ng buffer ng Logger"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Ipakita ang dialog na Hindi Tumutugon ang App para sa mga app sa background"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ipakita ang mga babala sa notification channel"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Nagpapakita ng babala sa screen kapag nag-post ang app ng notification nang walang wastong channel"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Magpatupad ng mga shortcut para sa mga notification ng pag-uusap"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Ipa-back up ang mga notification gamit ang long-lived na shortcut sa pagbabahagi para lumabas sa seksyong pag-uusap"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Puwersahang payagan ang mga app sa external"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ginagawang kwalipikado ang anumang app na mailagay sa external na storage, anuman ang mga value ng manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Sapilitang gawing resizable ang mga aktibidad"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index f41b8ff..daa3eed 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Pili daha az harcar ve ağ performansını iyileştirir"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bu geçiş, yalnızca istemci modu için MAC rastgele hale getirme davranışını etkiler.\nBu mod etkinleştirildiğinde, MAC rastgele seçimi etkin olan tüm ağların MAC adresleri, istemcinin ağla bağlantısının en son kesildiği zamana bağlı olarak ilişkilendirme sırasında yeniden rastgele seçilebilir. Cihaz 4 saat veya daha kısa süre içinde tekrar bağlanırsa yeniden rastgele hale getirme gerçekleşmez."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu mod etkinleştirildiğinde, bu cihaz MAC rastgele hale getirme işlevi açık olan bir ağa her bağlandığında cihazın MAC adresi değişebilir."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Sayaçlı"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Sayaçsız"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Günlük Kaydedici arabellek boyutları"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Arka plan uygulamalar için Uygulama Yanıt Vermiyor mesajını göster"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Bildirim kanalı uyarılarını göster"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bir uygulama geçerli kanal olmadan bildirim yayınladığında ekranda uyarı gösterir"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Görüşme bildirimleri için kısayolları zorunlu kıl"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Bildirimlerin, görüşme bölümünde görünebilmesi için uzun ömürlü paylaşma kısayolu ile desteklenmesini gerektir"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Harici birimdeki uygulamalara izin vermeye zorla"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest değerlerinden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Cihaz varsayılanı"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Devre dışı"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazının yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a6021d2..442c52e 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показати параметри сертифікації бездротового екрана"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зменшує споживання заряду акумулятора й підвищує ефективність роботи мережі"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Цей перемикач впливає на поведінку довільного вибору MAC-адрес лише для клієнтського режиму.\nКоли цей режим активовано, MAC-адреси мереж із довільним вибором цих адрес переназначаються під час зв\'язування залежно від часу останнього відключення клієнта від мережі. Повторний довільний вибір адрес не відбувається, якщо пристрій знову підключається протягом 4 годин."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Якщо цей режим увімкнено, MAC-адреса пристрою може змінюватися щоразу, коли він підключається до мережі з довільним вибором MAC-адрес."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"З тарифікацією трафіку"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Без тарифікації трафіку"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Розміри буфера журналу"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Показувати вікно \"Додаток не відповідає\" для додатків у фоновому режимі"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Показувати застереження про канал"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"З’являється застереження, коли додаток надсилає сповіщення через недійсний канал"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Використовувати ярлики для сповіщень про чати"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Вимагати для сповіщень постійних ярликів доступу, щоб показувати їх у розділі чатів"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Примусово записувати додатки в зовнішню пам’ять"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Можна записувати додатки в зовнішню пам’ять, незалежно від значень у маніфесті"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Примусово масштабувати активність"</string>
@@ -553,4 +551,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index a425805..463c161 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"بیٹری ڈرین کم کرتا ہے اور نیٹ ورک کارکردگی کو بہتر بناتا ہے"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"یہ ٹوگل صرف کلائنٹ وضع کے لئے MAC کی رینڈمائزیشن کو متاثر کرتا ہے۔\nجب یہ وضع فعال کی جاتی ہے، تو کسی بھی نیٹ ورکس میں جو MAC رینڈمائزیشن کو فعال کرتا ہے ان کے MAC ایڈریسز ایسوسی ایشن کے دوران دوبارہ رینڈمائز ہو سکتے ہیں، اس پر منحصر ہے کہ کلائنٹ کب آخری بار نیٹ ورک سے غیر منسلک ہوا۔ اگر آلہ 4 گھنٹوں یا اس سے کم وقت میں دوبارہ منسلک ہو، تو پھر دوبارہ رینڈمائزیشن کا امکان نہیں ہوتا ہے۔"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"جب یہ وضع فعال ہوتا ہے تو، اس آلہ کا MAC پتہ ہر بار تبدیل ہو سکتا ہے جب یہ کسی نیٹ ورک سے منسلک ہوتا ہے جس میں MAC ہے رینڈمائزیشن کو فعال کرتا ہے۔"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"میٹرڈ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"غیر میٹر شدہ"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"لاگر بفر کے سائز"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"پس منظر کی ایپس کیلئے \'ایپ جواب نہیں دے رہی ہے\' ڈائلاگ ڈسپلے کریں"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"چینل کی اطلاعی تنبیہات دکھائیں"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"کسی ایپ کی طرف سے درست چینل کے بغیر اطلاع پوسٹ ہونے پر آن اسکرین تنبیہ ڈسپلے کرتا ہے"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"بات چیت کی اطلاعات کے لیے شارٹ کٹس نافذ کریں"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"بات چیت کے سیکشن میں ظاہر ہونے کے لئے اطلاعات کو طویل مدت والے شیئرنگ شارٹ کٹ کے ذریعے حمایت کی ضرورت ہے"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"بیرونی پر ایپس کو زبردستی اجازت دیں"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
<string name="guest_nickname" msgid="6332276931583337261">"مہمان"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3089b70..762a246 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -148,12 +148,12 @@
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth modem"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Modem"</string>
<string name="tether_settings_title_all" msgid="8910259483383010470">"Modem rejimi"</string>
- <string name="managed_user_title" msgid="449081789742645723">"Barcha ishchi ilovalar"</string>
+ <string name="managed_user_title" msgid="449081789742645723">"Barcha ishga oid ilovalar"</string>
<string name="user_guest" msgid="6939192779649870792">"Mehmon"</string>
<string name="unknown" msgid="3544487229740637809">"Noma’lum"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"Foydalanuvchi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Ba’zi birlamchi sozlamalar o‘rnatilgan"</string>
- <string name="launch_defaults_none" msgid="8049374306261262709">"Birlamchi sozlamalar o‘rnatilmagan"</string>
+ <string name="launch_defaults_none" msgid="8049374306261262709">"Birlamchi sozlamalar belgilanmagan"</string>
<string name="tts_settings" msgid="8130616705989351312">"Nutq sintezi sozlamalari"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Nutq sintezi"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Nutq tezligi"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya sarfini tejaydi va tarmoq samaradorligini oshiradi"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bu sozlama faqat mijoz rejimida tasodifiy MAC manzillardan foydalanishga taʼsir qiladi.\nHar qanday tarmoqqa ulanishda mijoz oxirgi marta tarmoqdan qachon uzilganiga qarab tasodifiy MAC manzili qayta yaratiladi. Agar ulanish 4 soat yoki kamroq davom etsa, tasodifiy MAC manzili qayta yaratilmaydi."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyati mavjud tarmoqqa har safar ulanganda almashishi mumkin."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Trafik hisoblanadigan tarmoq"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Trafik hisobi yuritilmaydigan tarmoq"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi hajmi"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Ilova javob bermayotgani haqida xabar qilish"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Xabarlar kanali ogohlantirishlarini ko‘rsatish"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Yaroqli kanalsiz yuborilgan yangi ilova xabarnomalari haqida ogohlantirishlarni ko‘rsatish"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Suhbat bildirishnomalari uchun yorliqlardan majburiy foydalanish"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Bildirishnoma suhbat qismida chiqishi uchun uzoq koʻrinadigan belgilar yordamida ularni nusxalash kerak"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Tashqi xotira qurilmasidagi ilova dasturlariga majburiy ruxsat berish"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmon rejimini olib tashlash"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Qurilma standarti"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Yoqilmagan"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar qurilma oʻchib yonganda bajariladi. Hoziroq oʻchib yoqish yoki bekor qilish."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 32fbcc9..4f93fe3 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -205,9 +205,9 @@
<string name="apn_settings_not_available" msgid="1147111671403342300">"Cài đặt tên điểm truy cập không khả dụng cho người dùng này"</string>
<string name="enable_adb" msgid="8072776357237289039">"Gỡ lỗi qua USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Bật chế độ gỡ lỗi khi kết nối USB"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"Thu hồi ủy quyền gỡ lỗi USB"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"Thu hồi các lượt ủy quyền gỡ lỗi qua USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Gỡ lỗi qua Wi-Fi"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Chế độ gỡ lỗi khi có kết nối Wi-Fi"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Bật chế độ gỡ lỗi khi có kết nối Wi-Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Lỗi"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Gỡ lỗi qua Wi-Fi"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Để xem và sử dụng các thiết bị có sẵn, hãy bật tính năng gỡ lỗi qua Wi-Fi"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Giảm hao pin và cải thiện hiệu suất mạng"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Thao tác bật/tắt này chỉ ảnh hưởng đến hành vi tạo địa chỉ MAC ngẫu nhiên ở chế độ máy khách.\nKhi bạn kích hoạt chế độ này, tất cả các mạng đã bật tính năng tạo địa chỉ MAC ngẫu nhiên có thể tạo lại địa chỉ MAC ngẫu nhiên của chúng trong quá trình liên kết, tùy thuộc vào lần gần đây nhất máy khách ngắt kết nối với mạng. Các mạng này sẽ không thể tạo ngẫu nhiên lại nếu thiết bị kết nối lại trong vòng 4 giờ."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Khi bật chế độ này, địa chỉ MAC của thiết bị này có thể thay đổi mỗi lần thiết bị kết nối với mạng đã bật tính năng sử dụng địa chỉ MAC ngẫu nhiên."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Đo lượng dữ liệu"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Không đo lượng dữ liệu"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Kích thước bộ đệm của trình ghi nhật ký"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Hiện hộp thoại Ứng dụng không phản hồi cho các ứng dụng nền"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Hiện cảnh báo kênh thông báo"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Hiện cảnh báo trên màn hình khi ứng dụng đăng thông báo mà không có kênh hợp lệ"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Áp dụng lối tắt cho thông báo của cuộc trò chuyện"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Để xuất hiện trong phần cuộc trò chuyện, thông báo phải có sự hỗ trợ của lối tắt chia sẻ lâu dài"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Buộc cho phép các ứng dụng trên bộ nhớ ngoài"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cho phép ghi mọi ứng dụng đủ điều kiện vào bộ nhớ ngoài, bất kể giá trị tệp kê khai là gì"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Buộc các hoạt động có thể thay đổi kích thước"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Khách"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7270c2e..3d8b6d7 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -225,7 +225,7 @@
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"与设备配对"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"WLAN 配对码"</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_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"请确保设备已连接到同一网络。"</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"扫描二维码即可通过 WLAN 配对设备"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"正在配对设备…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"无法配对设备。可能是因为二维码不正确,或者设备未连接到同一网络。"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"提升 WLAN 日志记录级别(在 WLAN 选择器中显示每个 SSID 的 RSSI)"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗电量以及改善网络性能"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"此切换开关仅会影响客户端模式的 MAC 地址随机分配行为。\n此模式开启后,系统可能会为已启用随机分配 MAC 地址功能的所有网络在关联期间重新随机分配 MAC 地址,具体取决于客户端上次断开网络连接的时间。如果设备在 4 小时或更短时间内重新连接到网络,系统便不会执行重新随机分配操作。"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"启用此模式后,每当此设备连接到已启用随机分配 MAC 地址功能的网络时,它的 MAC 地址就可能会发生更改。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按流量计费"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不按流量计费"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"日志记录器缓冲区大小"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"为后台应用显示“应用无响应”对话框"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"显示通知渠道警告"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"当应用未经有效渠道发布通知时,在屏幕上显示警告"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"强制执行会话通知快捷方式"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"要求通知必须有长期共享快捷方式支持,才能显示在会话部分中"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"强制允许将应用写入外部存储设备"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"强制将活动设为可调整大小"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"访客"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 5d73f3e..b4905c7 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -23,7 +23,7 @@
<string name="wifi_fail_to_scan" msgid="2333336097603822490">"無法掃瞄網絡"</string>
<string name="wifi_security_none" msgid="7392696451280611452">"無"</string>
<string name="wifi_remembered" msgid="3266709779723179188">"已儲存"</string>
- <string name="wifi_disconnected" msgid="7054450256284661757">"已解除連接"</string>
+ <string name="wifi_disconnected" msgid="7054450256284661757">"已中斷連線"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"已停用"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP 設定失敗"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"網絡品質欠佳,因此無法連線"</string>
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"減低耗電量並改善網絡表現"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"此切換只會影響用戶端模式的 MAC 隨機處理。\n啟動此模式後,視乎用戶端上次中斷網絡連線的時間,系統可能會重新為任何已啟用 MAC 隨機處理的網絡在關聯期間隨機處理其 MAC 地址。如裝置在 4 小時或以內重新連線,系統便不會重新進行隨機處理。"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用此模式後,每次連接至已啟用 MAC 隨機處理的網絡時,此裝置的 MAC 位址都可能會變更。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"按用量收費"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"不限數據用量收費"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"為背景應用程式顯示「應用程式無回應」對話框"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"顯示通知渠道警告"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"當應用程式未經有效渠道發佈通知時,在螢幕上顯示警告"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"執行對話通知捷徑"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"通知必須採用永久共用捷徑,以便在對話部分中顯示"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"強制允許應用程式寫入到外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"在任何資訊清單值下,允許將所有符合資格的應用程式寫入到外部儲存完間"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"強制將活動設為可調整尺寸"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 6fefa31..9a3f2f9 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細記錄"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗電量以及改善網路效能"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"這個切換鈕只會影響用戶端模式的 MAC 隨機化行為。\n這個模式開啟時,任何已啟用 MAC 隨機化的網路可能會在建立關聯時重新將 MAC 位址隨機化 (取決於用戶端上次中斷連線的時間)。如果裝置在 4 個小時內重新連線,就不會進行重新隨機化作業。"</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"啟用這個模式後,每次連線到啟用了 MAC 隨機化的網路時,這部裝置的 MAC 位址都可能會有所變更。"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"計量付費"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"非計量付費"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"為背景應用程式顯示「應用程式無回應」對話方塊"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"顯示通知管道警告"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"當應用程式未經有效管道發布通知時,在畫面上顯示警告"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"強制執行對話通知捷徑"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"要求通知必須有永久分享捷徑支援,才能顯示在對話部分中"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"強制允許將應用程式寫入外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"將活動強制設為可調整大小"</string>
@@ -551,4 +549,14 @@
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
+ <!-- no translation found for cached_apps_freezer_device_default (2616594131750144342) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_disabled (4816382260660472042) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_enabled (8866703500183051546) -->
+ <skip />
+ <!-- no translation found for cached_apps_freezer_reboot_dialog_text (695330563489230096) -->
+ <skip />
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6cb24e6..86698f4 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Yehlisa ukuphela kwebhethri futhi ithuthukise ukusebenza kwenethiwekhi"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Lokhu kuguqula kuthinta ukuziphatha kokungahleliwe kwe-MAC kwemodi yeklayenti kuphela.\nLapho le modi yenziwe yasebenza, noma yimaphi amanethiwekhi anokungahleliwe kwe-MAC okunikwe amandla angase abe nekheli lawo le-MAC libe okungahleliwe kabusha phakathi nokuhlobana, kuya ngokuthi iklayenti igcine nini ukunqamula kusuka kunethiwekhi. Ukwenza kube okungahleliwe kabusha akuveli uma idivayisi ixhuma kabusha emahoreni angu-4 noma ngaphansi."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Uma le modi inikwe amandla, ikheli le-MAC lale divayisi lingashintsha njalo uma ixhuma kunethiwekhi ene-MAC engahleliwe enikwe amandla."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kulinganisiwe"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Akulinganiselwa"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Amasayizi weloga ngebhafa"</string>
@@ -373,8 +373,6 @@
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Uhlelo lokusebenza lwesibonisi aluphenduli kungxoxo yezinhlelo zokusebenza zangemuva"</string>
<string name="show_notification_channel_warnings" msgid="3448282400127597331">"Bonisa izexwayiso zesiteshi sesaziso"</string>
<string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Ibonisa isexwayiso esikusikrini uma uhlelo lokusebenza luthumela isaziso ngaphandle kwesiteshi esivumelekile"</string>
- <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Phoqelela izinqamuleli zezaziso zengxoxo"</string>
- <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kudinga ukuba izaziso zisekelwe yisinqamuleli sokwabelana sesikhathi eside ukuze zivele esigabeni sengxoxo"</string>
<string name="force_allow_on_external" msgid="9187902444231637880">"Phoqelela ukuvumela izinhlelo zokusebenza ngaphandle"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
@@ -551,4 +549,10 @@
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
+ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Idivayisi ezenzakalelayo"</string>
+ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string>
+ <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
+ <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
+ <!-- no translation found for accessibility_work_profile_app_description (5470883112342119165) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 7b589370..d59d698 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -633,4 +633,18 @@
<item>@color/bt_color_bg_7</item>
</integer-array>
+ <!-- Cached apps freezer modes -->
+ <array name="cached_apps_freezer_entries">
+ <item>@string/cached_apps_freezer_device_default</item>
+ <item>@string/cached_apps_freezer_enabled</item>
+ <item>@string/cached_apps_freezer_disabled</item>
+ </array>
+
+ <!-- Values for cached apps freezer modes -->
+ <array name="cached_apps_freezer_values">
+ <item>device_default</item>
+ <item>enabled</item>
+ <item>disabled</item>
+ </array>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7587cc1..e42e438 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -719,7 +719,7 @@
<!-- Setting Checkbox summary whether to disable Wifi scan throttling [CHAR LIMIT=NONE] -->
<string name="wifi_scan_throttling_summary">Reduces battery drain & improves network performance</string>
<!-- Setting Checkbox title whether to enable WiFi enhanced mac randomization. [CHAR LIMIT=NONE] -->
- <string name="wifi_enhanced_mac_randomization_summary">This toggle affects MAC randomization behavior for client mode only.\nWhen this mode is activated, any networks that have MAC randomization enabled may have their MAC addresses re\u2011randomized during association, depending on when the client last disconnected from the network. Re\u2011randomization does not occur if the device reconnects in 4 hours or less.</string>
+ <string name="wifi_enhanced_mac_randomization_summary">When this mode is enabled, this device\u2019s MAC address may change each time it connects to a network that has MAC randomization enabled.</string>
<!-- Label indicating network has been manually marked as metered -->
<string name="wifi_metered_label">Metered</string>
<!-- Label indicating network has been manually marked as unmetered -->
@@ -1365,4 +1365,15 @@
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
+ <!-- List entry in developer settings to choose default device/system behavior for the app freezer [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_device_default">Device default</string>
+ <!-- List entry in developer settings to disable the app freezer in developer settings [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_disabled">Disabled</string>
+ <!-- List entry in developer settings to enable the app freezer in developer settings [CHAR LIMIT=30]-->
+ <string name="cached_apps_freezer_enabled">Enabled</string>
+ <!-- Developer setting dialog prompting the user to reboot after changing the app freezer setting [CHAR LIMIT=NONE]-->
+ <string name="cached_apps_freezer_reboot_dialog_text">Your device must be rebooted for this change to apply. Reboot now or cancel.</string>
+
+ <!-- A content description for work profile app [CHAR LIMIT=35] -->
+ <string name="accessibility_work_profile_app_description">Work <xliff:g id="app_name" example="Camera">%s</xliff:g></string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index eb02a1c..a43412e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -29,8 +29,6 @@
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
-import androidx.annotation.NonNull;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.launcher3.icons.IconFactory;
@@ -457,19 +455,21 @@
return state;
}
- /**
- * Get the {@link Drawable} that represents the app icon
- */
- public static @NonNull Drawable getBadgedIcon(
- @NonNull Context context, @NonNull ApplicationInfo appInfo) {
- final UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
+ /** Get the corresponding adaptive icon drawable. */
+ public static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) {
try (IconFactory iconFactory = IconFactory.obtain(context)) {
- final Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
- appInfo.loadUnbadgedIcon(context.getPackageManager()), user, false).icon;
+ final Bitmap iconBmp = iconFactory.createBadgedIconBitmap(icon, user,
+ true /* shrinkNonAdaptiveIcons */).icon;
return new BitmapDrawable(context.getResources(), iconBmp);
}
}
+ /** Get the {@link Drawable} that represents the app icon */
+ public static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) {
+ return getBadgedIcon(context, appInfo.loadUnbadgedIcon(context.getPackageManager()),
+ UserHandle.getUserHandleForUid(appInfo.uid));
+ }
+
private static boolean isNotInIwlan(ServiceState serviceState) {
final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS,
diff --git a/packages/SettingsLib/src/com/android/settingslib/accounts/AuthenticatorHelper.java b/packages/SettingsLib/src/com/android/settingslib/accounts/AuthenticatorHelper.java
index ef511bb..4af9e3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accounts/AuthenticatorHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accounts/AuthenticatorHelper.java
@@ -32,6 +32,8 @@
import android.os.UserHandle;
import android.util.Log;
+import com.android.settingslib.Utils;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -116,7 +118,7 @@
if (icon == null) {
icon = context.getPackageManager().getDefaultActivityIcon();
}
- return icon;
+ return Utils.getBadgedIcon(mContext, icon, mUserHandle);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index c4ff719..b1f2a39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -26,6 +26,7 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.R;
@@ -129,7 +130,7 @@
*/
public static boolean isHiddenSystemModule(Context context, String packageName) {
return ApplicationsState.getInstance((Application) context.getApplicationContext())
- .isHiddenModule(packageName);
+ .isHiddenModule(packageName);
}
/**
@@ -140,4 +141,28 @@
.isSystemModule(packageName);
}
+ /**
+ * Returns a boolean indicating whether a given package is a mainline module.
+ */
+ public static boolean isMainlineModule(Context context, String packageName) {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ return pm.getModuleInfo(packageName, 0 /* flags */) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a content description of an app name which distinguishes a personal app from a
+ * work app for accessibility purpose.
+ * If the app is in a work profile, then add a "work" prefix to the app name.
+ */
+ public static String getAppContentDescription(Context context, String packageName,
+ int userId) {
+ final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName);
+ return UserManager.get(context).isManagedProfile(userId)
+ ? context.getString(R.string.accessibility_work_profile_app_description, appLabel)
+ : appLabel.toString();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
index 454d1dc..bd9e760 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
@@ -47,6 +47,7 @@
private final String mIntentAction;
private final String mPermission;
private final String mNoun;
+ private final boolean mAddDeviceLockedFlags;
private final HashSet<ComponentName> mEnabledServices = new HashSet<>();
private final List<ServiceInfo> mServices = new ArrayList<>();
private final List<Callback> mCallbacks = new ArrayList<>();
@@ -54,7 +55,8 @@
private boolean mListening;
private ServiceListing(Context context, String tag,
- String setting, String intentAction, String permission, String noun) {
+ String setting, String intentAction, String permission, String noun,
+ boolean addDeviceLockedFlags) {
mContentResolver = context.getContentResolver();
mContext = context;
mTag = tag;
@@ -62,6 +64,7 @@
mIntentAction = intentAction;
mPermission = permission;
mNoun = noun;
+ mAddDeviceLockedFlags = addDeviceLockedFlags;
}
public void addCallback(Callback callback) {
@@ -125,11 +128,15 @@
mServices.clear();
final int user = ActivityManager.getCurrentUser();
+ int flags = PackageManager.GET_SERVICES | PackageManager.GET_META_DATA;
+ if (mAddDeviceLockedFlags) {
+ flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
+
final PackageManager pmWrapper = mContext.getPackageManager();
List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
- new Intent(mIntentAction),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
- user);
+ new Intent(mIntentAction), flags, user);
for (ResolveInfo resolveInfo : installedServices) {
ServiceInfo info = resolveInfo.serviceInfo;
@@ -186,6 +193,7 @@
private String mIntentAction;
private String mPermission;
private String mNoun;
+ private boolean mAddDeviceLockedFlags = false;
public Builder(Context context) {
mContext = context;
@@ -216,8 +224,19 @@
return this;
}
+ /**
+ * Set to true to add support for both MATCH_DIRECT_BOOT_AWARE and
+ * MATCH_DIRECT_BOOT_UNAWARE flags when querying PackageManager. Required to get results
+ * prior to the user unlocking the device for the first time.
+ */
+ public Builder setAddDeviceLockedFlags(boolean addDeviceLockedFlags) {
+ mAddDeviceLockedFlags = addDeviceLockedFlags;
+ return this;
+ }
+
public ServiceListing build() {
- return new ServiceListing(mContext, mTag, mSetting, mIntentAction, mPermission, mNoun);
+ return new ServiceListing(mContext, mTag, mSetting, mIntentAction, mPermission, mNoun,
+ mAddDeviceLockedFlags);
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 002bbec..1d06df0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -108,10 +108,8 @@
final List<RoutingSessionInfo> infos = mRouterManager.getActiveSessions();
if (infos.size() > 0) {
final RoutingSessionInfo info = infos.get(0);
- final MediaRouter2Manager.RoutingController controller =
- mRouterManager.getControllerForSession(info);
+ mRouterManager.transfer(info, device.mRouteInfo);
- controller.transferToRoute(device.mRouteInfo);
isConnected = true;
}
return isConnected;
@@ -131,7 +129,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null && info.getSelectableRoutes().contains(device.mRouteInfo.getId())) {
- mRouterManager.getControllerForSession(info).selectRoute(device.mRouteInfo);
+ mRouterManager.selectRoute(info, device.mRouteInfo);
return true;
}
@@ -162,7 +160,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null && info.getSelectedRoutes().contains(device.mRouteInfo.getId())) {
- mRouterManager.getControllerForSession(info).deselectRoute(device.mRouteInfo);
+ mRouterManager.deselectRoute(info, device.mRouteInfo);
return true;
}
@@ -207,8 +205,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null) {
- for (MediaRoute2Info route : mRouterManager.getControllerForSession(info)
- .getSelectableRoutes()) {
+ for (MediaRoute2Info route : mRouterManager.getSelectableRoutes(info)) {
deviceList.add(new InfoMediaDevice(mContext, mRouterManager,
route, mPackageName));
}
@@ -235,8 +232,7 @@
final RoutingSessionInfo info = getRoutingSessionInfo();
if (info != null) {
- for (MediaRoute2Info route : mRouterManager.getControllerForSession(info)
- .getSelectedRoutes()) {
+ for (MediaRoute2Info route : mRouterManager.getSelectedRoutes(info)) {
deviceList.add(new InfoMediaDevice(mContext, mRouterManager,
route, mPackageName));
}
@@ -249,6 +245,15 @@
return deviceList;
}
+ void adjustSessionVolume(RoutingSessionInfo info, int volume) {
+ if (info == null) {
+ Log.w(TAG, "Unable to adjust session volume. RoutingSessionInfo is empty");
+ return;
+ }
+
+ mRouterManager.setSessionVolume(info, volume);
+ }
+
/**
* Adjust the volume of {@link android.media.RoutingSessionInfo}.
*
@@ -352,6 +357,10 @@
}
}
+ List<RoutingSessionInfo> getActiveMediaSession() {
+ return mRouterManager.getActiveSessions();
+ }
+
private void buildAvailableRoutes() {
for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
if (DEBUG) {
@@ -421,7 +430,7 @@
}
@Override
- public void onControlCategoriesChanged(String packageName, List<String> controlCategories) {
+ public void onPreferredFeaturesChanged(String packageName, List<String> preferredFeatures) {
if (TextUtils.equals(mPackageName, packageName)) {
refreshDevices();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index af69178..887a49b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -20,16 +20,20 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.media.RoutingSessionInfo;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.IntDef;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -256,22 +260,6 @@
}
/**
- * Find the active MediaDevice.
- *
- * @param type the media device type.
- * @return MediaDevice list
- */
- public List<MediaDevice> getActiveMediaDevice(@MediaDevice.MediaDeviceType int type) {
- final List<MediaDevice> devices = new ArrayList<>();
- for (MediaDevice device : mMediaDevices) {
- if (type == device.mType && device.getClientPackageName() != null) {
- devices.add(device);
- }
- }
- return devices;
- }
-
- /**
* Add a MediaDevice to let it play current media.
*
* @param device MediaDevice
@@ -319,6 +307,23 @@
/**
* Adjust the volume of session.
*
+ * @param sessionId the value of media session id
+ * @param volume the value of volume
+ */
+ public void adjustSessionVolume(String sessionId, int volume) {
+ final List<RoutingSessionInfo> infos = getActiveMediaSession();
+ for (RoutingSessionInfo info : infos) {
+ if (TextUtils.equals(sessionId, info.getId())) {
+ mInfoMediaManager.adjustSessionVolume(info, volume);
+ return;
+ }
+ }
+ Log.w(TAG, "adjustSessionVolume: Unable to find session: " + sessionId);
+ }
+
+ /**
+ * Adjust the volume of session.
+ *
* @param volume the value of volume
*/
public void adjustSessionVolume(int volume) {
@@ -352,6 +357,15 @@
return mInfoMediaManager.getSessionName();
}
+ /**
+ * Gets the current active session.
+ *
+ * @return current active session list{@link android.media.RoutingSessionInfo}
+ */
+ public List<RoutingSessionInfo> getActiveMediaSession() {
+ return mInfoMediaManager.getActiveMediaSession();
+ }
+
private MediaDevice updateCurrentConnectedDevice() {
MediaDevice phoneMediaDevice = null;
for (MediaDevice device : mMediaDevices) {
@@ -419,7 +433,8 @@
cachedDeviceManager.findDevice(device);
if (cachedDevice != null) {
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
- && !cachedDevice.isConnected()) {
+ && !cachedDevice.isConnected()
+ && isA2dpOrHearingAidDevice(cachedDevice)) {
deviceCount++;
cachedBluetoothDeviceList.add(cachedDevice);
if (deviceCount >= MAX_DISCONNECTED_DEVICE_NUM) {
@@ -443,6 +458,15 @@
return new ArrayList<>(mDisconnectedMediaDevices);
}
+ private boolean isA2dpOrHearingAidDevice(CachedBluetoothDevice device) {
+ for (LocalBluetoothProfile profile : device.getConnectableProfiles()) {
+ if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void onDeviceRemoved(MediaDevice device) {
if (mMediaDevices.contains(device)) {
@@ -465,10 +489,7 @@
if (connectDevice != null) {
connectDevice.setState(MediaDeviceState.STATE_CONNECTED);
}
- if (connectDevice == mCurrentConnectedDevice) {
- Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
- return;
- }
+
mCurrentConnectedDevice = connectDevice;
dispatchSelectedDeviceStateChanged(mCurrentConnectedDevice,
MediaDeviceState.STATE_CONNECTED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index f1c0f6b..139a12c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,18 +31,14 @@
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.text.TextUtils;
-import android.util.Log;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
-import com.android.settingslib.R;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -180,7 +176,7 @@
*/
public void requestSetVolume(int volume) {
- mRouterManager.requestSetVolume(mRouteInfo, volume);
+ mRouterManager.setRouteVolume(mRouteInfo, volume);
}
/**
@@ -215,30 +211,6 @@
*
* @return application label.
*/
- public String getClientAppLabel() {
- final String packageName = mRouteInfo.getClientPackageName();
- if (TextUtils.isEmpty(packageName)) {
- Log.d(TAG, "Client package name is empty");
- return mContext.getResources().getString(R.string.unknown);
- }
- try {
- final PackageManager packageManager = mContext.getPackageManager();
- final String appLabel = packageManager.getApplicationLabel(
- packageManager.getApplicationInfo(packageName, 0)).toString();
- if (!TextUtils.isEmpty(appLabel)) {
- return appLabel;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "unable to find " + packageName);
- }
- return mContext.getResources().getString(R.string.unknown);
- }
-
- /**
- * Get application label from MediaDevice.
- *
- * @return application label.
- */
public int getDeviceType() {
return mType;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 42f2542..8ea5ff1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -41,7 +41,10 @@
private static final String TAG = "PhoneMediaDevice";
- public static final String ID = "phone_media_device_id_1";
+ public static final String PHONE_ID = "phone_media_device_id";
+ // For 3.5 mm wired headset
+ public static final String WIRED_HEADSET_ID = "wired_headset_media_device_id";
+ public static final String USB_HEADSET_ID = "usb_headset_media_device_id";
private String mSummary = "";
@@ -109,7 +112,25 @@
@Override
public String getId() {
- return ID;
+ String id;
+ switch (mRouteInfo.getType()) {
+ case TYPE_WIRED_HEADSET:
+ case TYPE_WIRED_HEADPHONES:
+ id = WIRED_HEADSET_ID;
+ break;
+ case TYPE_USB_DEVICE:
+ case TYPE_USB_HEADSET:
+ case TYPE_USB_ACCESSORY:
+ case TYPE_DOCK:
+ case TYPE_HDMI:
+ id = USB_HEADSET_ID;
+ break;
+ case TYPE_BUILTIN_SPEAKER:
+ default:
+ id = PHONE_ID;
+ break;
+ }
+ return id;
}
@Override
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 76eea67..99c568a 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
@@ -136,7 +136,7 @@
}
@Test
- public void onControlCategoriesChanged_samePackageName_shouldAddMediaDevice() {
+ public void onPreferredFeaturesChanged_samePackageName_shouldAddMediaDevice() {
final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
routingSessionInfos.add(sessionInfo);
@@ -156,7 +156,7 @@
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
- mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged(TEST_PACKAGE_NAME, null);
+ mInfoMediaManager.mMediaRouterCallback.onPreferredFeaturesChanged(TEST_PACKAGE_NAME, null);
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
@@ -165,8 +165,8 @@
}
@Test
- public void onControlCategoriesChanged_differentPackageName_doNothing() {
- mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged("com.fake.play", null);
+ public void onPreferredFeaturesChanged_differentPackageName_doNothing() {
+ mInfoMediaManager.mMediaRouterCallback.onPreferredFeaturesChanged("com.fake.play", null);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(0);
}
@@ -416,6 +416,11 @@
}
@Test
+ public void adjustSessionVolume_routingSessionInfoIsNull_noCrash() {
+ mInfoMediaManager.adjustSessionVolume(null, 10);
+ }
+
+ @Test
public void adjustSessionVolume_packageNameIsNull_noCrash() {
mInfoMediaManager.mPackageName = null;
@@ -487,6 +492,14 @@
}
@Test
+ public void getActiveMediaSession_returnActiveSession() {
+ final List<RoutingSessionInfo> infos = new ArrayList<>();
+ mShadowRouter2Manager.setActiveSessions(infos);
+
+ assertThat(mInfoMediaManager.getActiveMediaSession()).containsExactlyElementsIn(infos);
+ }
+
+ @Test
public void releaseSession_packageNameIsNull_returnFalse() {
mInfoMediaManager.mPackageName = null;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index f3b49a6..365a16c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -34,12 +34,14 @@
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.media.RoutingSessionInfo;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
@@ -67,6 +69,7 @@
private static final String TEST_DEVICE_ID_3 = "device_id_3";
private static final String TEST_CURRENT_DEVICE_ID = "currentDevice_id";
private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
+ private static final String TEST_SESSION_ID = "session_id";
@Mock
private InfoMediaManager mInfoMediaManager;
@@ -526,40 +529,6 @@
}
@Test
- public void getActiveMediaDevice_checkList() {
- final List<MediaDevice> devices = new ArrayList<>();
- final MediaDevice device1 = mock(MediaDevice.class);
- final MediaDevice device2 = mock(MediaDevice.class);
- final MediaDevice device3 = mock(MediaDevice.class);
- device1.mType = MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE;
- device2.mType = MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE;
- device3.mType = MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE;
- when(device1.getClientPackageName()).thenReturn(TEST_DEVICE_ID_1);
- when(device2.getClientPackageName()).thenReturn(TEST_DEVICE_ID_2);
- when(device3.getClientPackageName()).thenReturn(TEST_DEVICE_ID_3);
- when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
- when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
- when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
- devices.add(device1);
- devices.add(device2);
- devices.add(device3);
- mLocalMediaManager.registerCallback(mCallback);
- mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
-
- List<MediaDevice> activeDevices = mLocalMediaManager.getActiveMediaDevice(
- MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
- assertThat(activeDevices).containsExactly(device1);
-
- activeDevices = mLocalMediaManager.getActiveMediaDevice(
- MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
- assertThat(activeDevices).containsExactly(device2);
-
- activeDevices = mLocalMediaManager.getActiveMediaDevice(
- MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
- assertThat(activeDevices).containsExactly(device3);
- }
-
- @Test
public void onDeviceAttributesChanged_shouldBeCalled() {
mLocalMediaManager.registerCallback(mCallback);
@@ -569,6 +538,18 @@
}
@Test
+ public void getActiveMediaSession_verifyCorrectSession() {
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+ when(info.getId()).thenReturn(TEST_SESSION_ID);
+ routingSessionInfos.add(info);
+ when(mInfoMediaManager.getActiveMediaSession()).thenReturn(routingSessionInfos);
+
+ assertThat(mLocalMediaManager.getActiveMediaSession().get(0).getId())
+ .matches(TEST_SESSION_ID);
+ }
+
+ @Test
public void onDeviceListAdded_haveDisconnectedDevice_addDisconnectedDevice() {
final List<MediaDevice> devices = new ArrayList<>();
final MediaDevice device1 = mock(MediaDevice.class);
@@ -580,6 +561,10 @@
mLocalMediaManager.mMediaDevices.add(device3);
mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+ final List<LocalBluetoothProfile> profiles = new ArrayList<>();
+ final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
+ profiles.add(a2dpProfile);
+
final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
@@ -591,6 +576,7 @@
when(cachedManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(cachedDevice.isConnected()).thenReturn(false);
+ when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
@@ -654,6 +640,10 @@
mLocalMediaManager.mMediaDevices.add(device3);
mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+ final List<LocalBluetoothProfile> profiles = new ArrayList<>();
+ final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
+ profiles.add(a2dpProfile);
+
final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
final BluetoothDevice bluetoothDevice2 = mock(BluetoothDevice.class);
@@ -682,6 +672,7 @@
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(cachedDevice.isConnected()).thenReturn(false);
when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
+ when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
when(bluetoothDevice.getBluetoothClass()).thenReturn(bluetoothClass);
when(bluetoothClass.getDeviceClass()).thenReturn(AUDIO_VIDEO_HEADPHONES);
@@ -721,4 +712,17 @@
assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
verify(mCallback).onDeviceListUpdate(any());
}
+
+ @Test
+ public void adjustSessionVolume_verifyCorrectSessionVolume() {
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+ when(info.getId()).thenReturn(TEST_SESSION_ID);
+ routingSessionInfos.add(info);
+ when(mInfoMediaManager.getActiveMediaSession()).thenReturn(routingSessionInfos);
+
+ mLocalMediaManager.adjustSessionVolume(TEST_SESSION_ID, 10);
+
+ verify(mInfoMediaManager).adjustSessionVolume(info, 10);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 6664870..47d4beb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -29,13 +29,9 @@
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageStats;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
-import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -49,8 +45,6 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -70,8 +64,6 @@
private static final String ROUTER_ID_2 = "RouterId_2";
private static final String ROUTER_ID_3 = "RouterId_3";
private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
- private static final String TEST_PACKAGE_NAME2 = "com.test.playmusic2";
- private static final String TEST_APPLICATION_LABEL = "playmusic";
private final BluetoothClass mHeadreeClass =
new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
private final BluetoothClass mCarkitClass =
@@ -125,10 +117,6 @@
private InfoMediaDevice mInfoMediaDevice3;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private PhoneMediaDevice mPhoneMediaDevice;
- private ShadowPackageManager mShadowPackageManager;
- private ApplicationInfo mAppInfo;
- private PackageInfo mPackageInfo;
- private PackageStats mPackageStats;
@Before
public void setUp() {
@@ -459,41 +447,6 @@
assertThat(mInfoMediaDevice1.getClientPackageName()).isEqualTo(TEST_PACKAGE_NAME);
}
- private void initPackage() {
- mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
- mAppInfo = new ApplicationInfo();
- mAppInfo.flags = ApplicationInfo.FLAG_INSTALLED;
- mAppInfo.packageName = TEST_PACKAGE_NAME;
- mAppInfo.name = TEST_APPLICATION_LABEL;
- mPackageInfo = new PackageInfo();
- mPackageInfo.packageName = TEST_PACKAGE_NAME;
- mPackageInfo.applicationInfo = mAppInfo;
- mPackageStats = new PackageStats(TEST_PACKAGE_NAME);
- }
-
- @Test
- public void getClientAppLabel_matchedPackageName_returnLabel() {
- initPackage();
- when(mRouteInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(
- mContext.getResources().getString(R.string.unknown));
-
- mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(TEST_APPLICATION_LABEL);
- }
-
- @Test
- public void getClientAppLabel_noMatchedPackageName_returnDefault() {
- initPackage();
- mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
- when(mRouteInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME2);
-
- assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(
- mContext.getResources().getString(R.string.unknown));
- }
-
@Test
public void setState_verifyGetState() {
mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 6f265dd..47f6fe3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -21,6 +21,10 @@
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static com.android.settingslib.media.PhoneMediaDevice.PHONE_ID;
+import static com.android.settingslib.media.PhoneMediaDevice.USB_HEADSET_ID;
+import static com.android.settingslib.media.PhoneMediaDevice.WIRED_HEADSET_ID;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@@ -108,4 +112,22 @@
assertThat(mPhoneMediaDevice.getName())
.isEqualTo(mContext.getString(R.string.media_transfer_this_device_name));
}
+
+ @Test
+ public void getId_returnCorrectId() {
+ when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(WIRED_HEADSET_ID);
+
+ when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(USB_HEADSET_ID);
+
+ when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
+
+ assertThat(mPhoneMediaDevice.getId())
+ .isEqualTo(PHONE_ID);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index d023d98..028c304 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -225,8 +225,7 @@
@VisibleForTesting
public boolean isReplacedSystemSetting(String setting) {
// This list should not be modified.
- if (!Settings.System.MASTER_MONO.equals(setting)
- && !Settings.System.SCREEN_OFF_TIMEOUT.equals(setting)) {
+ if (!Settings.System.SCREEN_OFF_TIMEOUT.equals(setting)) {
return false;
}
// If this flag is set, values for the system settings from the list above have been
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a5dce6d..3d7559b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -376,6 +376,9 @@
Settings.Global.BUGREPORT_IN_POWER_MENU,
GlobalSettingsProto.BUGREPORT_IN_POWER_MENU);
dumpSetting(s, p,
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED,
+ GlobalSettingsProto.CACHED_APPS_FREEZER_ENABLED);
+ dumpSetting(s, p,
Settings.Global.CALL_AUTO_RETRY,
GlobalSettingsProto.CALL_AUTO_RETRY);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
index ca841a5..5e5a9d9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
@@ -44,7 +44,8 @@
// create channel, or update it if it already exists
NotificationChannel channel = new NotificationChannel(
SystemNotificationChannels.NETWORK_STATUS,
- context.getString(android.R.string.notification_channel_network_status),
+ context.getString(
+ com.android.internal.R.string.notification_channel_network_status),
NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(channel);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f5589d7..29c31ea 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -264,6 +264,7 @@
Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+ Settings.Global.ENABLE_RESTRICTED_BUCKET,
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
@@ -585,8 +586,10 @@
Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT,
Settings.Global.POWER_BUTTON_LONG_PRESS,
Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, // Temporary for R beta
Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
- Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT);
+ Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 7fac740..8086fd2 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3701846017049540910">"Protecció"</string>
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"Informes d\'errors"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"S\'està generant l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"S\'ha capturat l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Selecciona per compartir l\'informe d\'errors sense captura de pantalla o espera que es faci la captura"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Toca per compartir l\'informe d\'errors sense captura de pantalla o espera que es creï la captura"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Toca per compartir l\'informe d\'errors sense captura de pantalla o espera que es creï la captura"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Els informes d\'errors contenen dades dels diferents fitxers de registre del sistema, inclosa informació que pot ser confidencial (com ara l\'ús d\'aplicacions i les dades d\'ubicació). Comparteix-los només amb aplicacions i persones de confiança."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Els informes d\'errors contenen dades dels diferents fitxers de registre del sistema, que poden incloure informació sensible (com ara l\'ús d\'aplicacions i les dades d\'ubicació). Comparteix els informes d\'errors només amb aplicacions i persones de confiança."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"No ho tornis a mostrar"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'errors"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No s\'ha pogut llegir el fitxer de l\'informe d\'errors"</string>
diff --git a/packages/Shell/res/values-eu/strings.xml b/packages/Shell/res/values-eu/strings.xml
index 9695e41..2957dab 100644
--- a/packages/Shell/res/values-eu/strings.xml
+++ b/packages/Shell/res/values-eu/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"Akatsen txostenak"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egiten ari gara"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egin da"</string>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index d4bb3c6..dd4100c 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -25,19 +25,19 @@
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"گزارش مشکل بهزودی در تلفن نشان داده میشود"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"برای همرسانی گزارش اشکالتان، انتخاب کنید"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"برای همرسانی گزارش اشکال، ضربه بزنید"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"انتخاب کنید تا گزارش اشکالتان بدون عکس صفحهنمایش به اشتراک گذاشته شود یا منتظر بمانید گرفتن عکس از صفحهنمایش تمام شود"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون عکس صفحهنمایش، ضربه بزنید یا صبر کنید تا عکس صفحهنمایش گرفته شود."</string>
- <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون عکس صفحهنمایش، ضربه بزنید یا صبر کنید تا عکس صفحهنمایش گرفته شود."</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"گزارشهای اشکال حاوی دادههایی از فایلهای مختلف گزارش سیستم هستند، که ممکن است حاوی دادههای حساس شما (از قبیل دادههای استفاده از برنامه و مکان) باشند. گزارشهای اشکال را فقط با افراد و برنامههایی که به آنها اعتماد دارید به اشتراک بگذارید."</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"انتخاب کنید تا گزارش اشکالتان بدون نماگرفت به اشتراک گذاشته شود یا منتظر بمانید گرفتن عکس از صفحهنمایش تمام شود"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون نماگرفت، ضربه بزنید یا صبر کنید تا نماگرفت گرفته شود."</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"برای اشتراکگذاری گزارش مشکل بدون نماگرفت، ضربه بزنید یا صبر کنید تا نماگرفت گرفته شود."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"گزارشهای اشکال حاوی دادههایی از فایلهای مختلف گزارش سیستم هستند، که ممکن است حاوی دادههای حساس شما (از قبیل دادههای استفاده از برنامه و مکان) باشند. گزارشهای اشکال را فقط با افراد و برنامههایی که به آنها اعتماد دارید بهاشتراک بگذارید."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"دوباره نشان داده نشود"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"گزارش اشکال"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"فایل گزارش اشکال خوانده نشد"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"جزئیات گزارش اشکال به فایل ZIP اضافه نشد"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"بینام"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"جزئیات"</string>
- <string name="bugreport_screenshot_action" msgid="8677781721940614995">"عکس صفحهنمایش"</string>
- <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"عکس صفحهنمایش با موفقیت گرفته شد."</string>
- <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمیتوان عکس صفحهنمایش گرفت."</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"نماگرفت"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"نماگرفت با موفقیت گرفته شد."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمیتوان نماگرفت گرفت."</string>
<string name="bugreport_info_dialog_title" msgid="1355948594292983332">"جزئیات گزارش اشکال <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
<string name="bugreport_info_title" msgid="2306030793918239804">"عنوان اشکال"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 5c5ba816..dd8ed22 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"Laporan bug"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan bug <xliff:g id="ID">#%d</xliff:g> sedang dibuat"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan bug <xliff:g id="ID">#%d</xliff:g> dijepret"</string>
diff --git a/packages/Shell/res/values-kk/strings.xml b/packages/Shell/res/values-kk/strings.xml
index 82c02a1..60e58fe 100644
--- a/packages/Shell/res/values-kk/strings.xml
+++ b/packages/Shell/res/values-kk/strings.xml
@@ -28,9 +28,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Қате туралы есепті скриншотсыз бөлісу үшін таңдаңыз немесе скриншот түсіріліп болғанша күтіңіз"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Қате туралы есепті скриншотсыз бөлісу үшін түртіңіз немесе скриншот сақталып болғанша күтіңіз"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Қате туралы есепті скриншотсыз бөлісу үшін түртіңіз немесе скриншот сақталып болғанша күтіңіз"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"Қате туралы есептерде жүйенің әртүрлі журнал файлдарының деректері беріледі. Олар маңызды деректерді қамтуы мүмкін (мысалы, қолданбаны пайдалану және орналасқан жер деректері). Қате туралы есептерді тек сенімді адамдармен және қолданбалармен бөлісіңіз."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"Қате туралы есептерде жүйенің түрлі журнал файлдарының деректері қамтылады. Оларда сіз құпия деп есептейтін деректер (мысалы, қолданбаны пайдалану және орналасқан жер деректері) болуы мүмкін. Қате туралы есептерді тек сенімді адамдармен және қолданбалармен бөлісіңіз."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Қайтадан көрсетілмесін"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы баяндамалар"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы есептер"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Қате туралы есеп файлын оқу мүмкін болмады"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Қате туралы есеп мәліметтері zip файлына салынбады"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"атаусыз"</string>
diff --git a/packages/Shell/res/values-my/strings.xml b/packages/Shell/res/values-my/strings.xml
index 7e7b763..2376ffd 100644
--- a/packages/Shell/res/values-my/strings.xml
+++ b/packages/Shell/res/values-my/strings.xml
@@ -30,7 +30,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ချွတ်ယွင်းချက်အစီရင်ခံစာကို ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းမပါဘဲ မျှဝေရန် တို့ပါ သို့မဟုတ် ဖန်သားပြင်ဓာတ်ပုံမှတ်တမ်းတင်ခြင်း ပြီးဆုံးသည်အထိ စောင့်ပါ"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"ချွတ်ယွင်းချက်အစီရင်ခံစာများတွင် သင့်အတွက် အရေးကြီးသည့် ဒေတာများ (အက်ပ်အသုံးပြုမှုနှင့် တည်နေရာအချက်အလက် ကဲ့သို့) ပါဝင်သည့် စနစ်၏မှတ်တမ်းဖိုင်မျိုးစုံပါဝင်ပါသည်။ ချွတ်ယွင်းချက်အစီရင်ခံစာများကို သင်ယုံကြည်စိတ်ချရသည့်လူများ၊ အက်ပ်များနှင့်သာ မျှဝေပါ။"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"နောက်ထပ်မပြပါနှင့်"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"ချို့ယွင်းမှု အစီရင်ခံစာများ"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"ချွတ်ယွင်းမှု အစီရင်ခံစာများ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို ဖတ်၍မရပါ"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"ဇစ်ဖိုင်သို့ ချွတ်ယွင်းချက် အစီရင်ခံစာအသေးစိတ် အချက်အလက်များကို ထည့်၍မရပါ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"အမည်မဲ့"</string>
diff --git a/packages/Shell/res/values-ne/strings.xml b/packages/Shell/res/values-ne/strings.xml
index 05ff412..7cc2e6b 100644
--- a/packages/Shell/res/values-ne/strings.xml
+++ b/packages/Shell/res/values-ne/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"तपाईंको बग रिपोर्ट स्क्रिनसट बिना आदान प्रदान गर्नाका लागि चयन गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुने प्रतीक्षा गर्नुहोस्"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नाका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"तपाईँको बग रिपोर्टलाई स्क्रिनसट बिना साझेदारी गर्नाका लागि ट्याप गर्नुहोस् वा स्क्रिनसट लिने प्रक्रिया पूरा हुन प्रतीक्षा गर्नुहोस्"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूको डेटा हुन्छ जसमा तपाईँले संवेदनशील मानेको डेटा समावेश हुन सक्छ (जस्तै अनुप्रयोगको प्रयोग र स्थानसम्बन्धी डेटा)। तपाईँले विश्वास गर्ने व्यक्ति र अनुप्रयोगहरूसँग मात्र बग रिपोर्टहरूलाई साझेदारी गर्नुहोस्।"</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"बग रिपोर्टमा प्रणालीका विभिन्न लग फाइलहरूको डेटा हुन्छ। यस रिपोर्टमा (अनुप्रयोगको प्रयोग र स्थानसम्बन्धी डेटा जस्ता) जसमा तपाईंका संवेदनशील डेटा समावेश हुन सक्छ । आफूले विश्वास गर्ने व्यक्ति र अनुप्रयोगहरूसँग मात्र बग रिपोर्ट सेयर गर्नुहोस्।"</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"फेरि नदेखाउनुहोस्"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल पढ्न सकिएन"</string>
@@ -43,5 +43,5 @@
<string name="bugreport_info_title" msgid="2306030793918239804">"बगको शीर्षक"</string>
<string name="bugreport_info_description" msgid="5072835127481627722">"बगको सारांश"</string>
<string name="save" msgid="4781509040564835759">"सुरक्षित गर्नुहोस्"</string>
- <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"बग रिपोर्ट साझेदारी गर्नुहोस्"</string>
+ <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"बग रिपोर्ट सेयर गर्नुहोस्"</string>
</resources>
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index bed7367..bb0496a 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ నివేదికల్లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం మరియు స్థాన డేటా వంటి) డేటాతో సహా సిస్టమ్కు సంబంధించిన విభిన్న లాగ్ ఫైల్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్లు మరియు వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ నివేదికల్లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేషన్ డేటా వంటి) డేటాతో పాటు సిస్టమ్కు సంబంధించిన విభిన్న లాగ్ ఫైల్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"మళ్లీ చూపవద్దు"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్ను చదవడం సాధ్యపడలేదు"</string>
diff --git a/packages/SimAppDialog/res/values-ta/strings.xml b/packages/SimAppDialog/res/values-ta/strings.xml
new file mode 100644
index 0000000..efcbc1b
--- /dev/null
+++ b/packages/SimAppDialog/res/values-ta/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="8898068901680117589">"சிம் ஆப்ஸ் உரையாடல்"</string>
+ <string name="install_carrier_app_title" msgid="334729104862562585">"மொபைல் சேவையை இயக்கு"</string>
+ <string name="install_carrier_app_description" msgid="4014303558674923797">"உங்கள் புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் <xliff:g id="ID_1">%1$s</xliff:g> ஆப்ஸை நிறுவ வேண்டும்"</string>
+ <string name="install_carrier_app_description_default" msgid="7356830245205847840">"உங்கள் புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் மொபைல் நிறுவன ஆப்ஸை நிறுவ வேண்டும்"</string>
+ <string name="install_carrier_app_defer_action" msgid="2558576736886876209">"இப்போது வேண்டாம்"</string>
+ <string name="install_carrier_app_download_action" msgid="7859229305958538064">"ஆப்ஸைப் பதிவிறக்கு"</string>
+</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index f63365b..7a27676 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -63,6 +63,8 @@
"androidx.lifecycle_lifecycle-extensions",
"androidx.dynamicanimation_dynamicanimation",
"androidx-constraintlayout_constraintlayout",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
@@ -127,6 +129,8 @@
"androidx.lifecycle_lifecycle-extensions",
"androidx.dynamicanimation_dynamicanimation",
"androidx-constraintlayout_constraintlayout",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1306657..61b1e30 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -692,6 +692,7 @@
</activity>
<activity android:name=".controls.management.ControlsFavoritingActivity"
+ android:label="@string/controls_favorite_default_title"
android:theme="@style/Theme.ControlsManagement"
android:excludeFromRecents="true"
android:showForAllUsers="true"
@@ -718,7 +719,7 @@
android:finishOnCloseSystemDialogs="true"
android:showForAllUsers="true"
android:clearTaskOnLaunch="true"
- android:launchMode="singleTask"
+ android:launchMode="singleInstance"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
index f6f8f53..d43aaf0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java
@@ -19,6 +19,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@ProvidesInterface(version = DetailAdapter.VERSION)
@@ -44,4 +45,18 @@
default boolean hasHeader() {
return true;
}
+
+ default UiEventLogger.UiEventEnum openDetailEvent() {
+ return INVALID;
+ }
+
+ default UiEventLogger.UiEventEnum closeDetailEvent() {
+ return INVALID;
+ }
+
+ default UiEventLogger.UiEventEnum moreSettingsEvent() {
+ return INVALID;
+ }
+
+ UiEventLogger.UiEventEnum INVALID = () -> 0;
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index e586c38..aeedc16 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -20,6 +20,7 @@
import android.metrics.LogMaker;
import android.service.quicksettings.Tile;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.qs.QSTile.Callback;
@@ -81,6 +82,18 @@
return logMaker;
}
+ /**
+ * Return a string to be used to identify the tile in UiEvents.
+ */
+ default String getMetricsSpec() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * Return an {@link InstanceId} to be used to identify the tile in UiEvents.
+ */
+ InstanceId getInstanceId();
+
@ProvidesInterface(version = Callback.VERSION)
public interface Callback {
public static final int VERSION = 1;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 6c4cbdf..d881cb6 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -40,6 +40,11 @@
boolean isDozing();
/**
+ * Is device pulsing.
+ */
+ boolean isPulsing();
+
+ /**
* Adds a state listener
*/
void addCallback(StateListener listener);
diff --git a/packages/SystemUI/res/drawable/control_spinner_background.xml b/packages/SystemUI/res/drawable/control_spinner_background.xml
index 999a77c..7a8728d 100644
--- a/packages/SystemUI/res/drawable/control_spinner_background.xml
+++ b/packages/SystemUI/res/drawable/control_spinner_background.xml
@@ -16,7 +16,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack"
- android:paddingStart="0dp"
+ android:paddingStart="40dp"
android:paddingEnd="40dp"
android:paddingLeft="0dp"
android:paddingRight="0dp">
diff --git a/packages/SystemUI/res/drawable/controls_list_divider_inset.xml b/packages/SystemUI/res/drawable/controls_list_divider_inset.xml
new file mode 100644
index 0000000..ddfa18c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_list_divider_inset.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/controls_list_divider"
+ android:insetRight="@dimen/control_spinner_padding_horizontal"
+ android:insetLeft="@dimen/control_spinner_padding_horizontal" />
diff --git a/packages/SystemUI/res/drawable/qs_media_background.xml b/packages/SystemUI/res/drawable/qs_media_background.xml
index 2821e4c..e79c9a4 100644
--- a/packages/SystemUI/res/drawable/qs_media_background.xml
+++ b/packages/SystemUI/res/drawable/qs_media_background.xml
@@ -14,13 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating" />
- <corners
- android:bottomLeftRadius="@dimen/qs_media_corner_radius"
- android:topLeftRadius="@dimen/qs_media_corner_radius"
- android:bottomRightRadius="@dimen/qs_media_corner_radius"
- android:topRightRadius="@dimen/qs_media_corner_radius"
- />
-</shape>
\ No newline at end of file
+<com.android.systemui.media.IlluminationDrawable
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ systemui:rippleMinSize="30dp"
+ systemui:rippleMaxSize="135dp"
+ systemui:highlight="15"
+ systemui:cornerRadius="@dimen/qs_media_corner_radius" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
index 163015b7..21013c6 100644
--- a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
+++ b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
@@ -17,6 +17,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:angle="90"
- android:startColor="#1f000000"
+ android:startColor="@color/global_screenshot_background_protection_start"
android:endColor="#00000000"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_overflow_view.xml b/packages/SystemUI/res/layout/bubble_overflow_view.xml
index 88a05ec..1ed1f07 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_view.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_view.xml
@@ -36,6 +36,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:maxLines="1"
+ android:lines="2"
+ android:ellipsize="end"
android:layout_gravity="center"
android:paddingTop="@dimen/bubble_overflow_text_padding"
android:gravity="center"/>
diff --git a/packages/SystemUI/res/layout/controls_app_item.xml b/packages/SystemUI/res/layout/controls_app_item.xml
index d54cd6d..a208098 100644
--- a/packages/SystemUI/res/layout/controls_app_item.xml
+++ b/packages/SystemUI/res/layout/controls_app_item.xml
@@ -16,33 +16,25 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="64dp"
android:background="?android:attr/selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="start|top"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:layout_marginBottom="@dimen/controls_app_bottom_margin">
+ android:gravity="center_vertical">
<FrameLayout
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:minWidth="56dp"
+ android:layout_height="match_parent"
android:orientation="horizontal"
- android:paddingTop="@dimen/controls_app_icon_frame_top_padding"
- android:paddingBottom="@dimen/controls_app_icon_frame_top_padding"
- android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"
- android:paddingStart="@dimen/controls_app_icon_frame_side_padding" >
+ android:paddingEnd="@dimen/controls_app_icon_frame_side_padding">
<ImageView
android:id="@android:id/icon"
+ android:layout_gravity="start|center_vertical"
android:layout_width="@dimen/controls_app_icon_size"
android:layout_height="@dimen/controls_app_icon_size" />
</FrameLayout>
@@ -51,9 +43,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:orientation="vertical"
- android:paddingTop="@dimen/controls_app_text_padding"
- android:paddingBottom="@dimen/controls_app_text_padding">
+ android:orientation="vertical">
<TextView
android:id="@android:id/title"
@@ -62,8 +52,7 @@
android:ellipsize="end"
android:fadingEdge="horizontal"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorPrimary"/>
+ android:textAppearance="@style/TextAppearance.Control.Management.Subtitle"/>
<TextView
android:id="@+id/favorites"
@@ -81,7 +70,5 @@
android:layout_width="match_parent"
android:layout_height="@dimen/controls_app_divider_height"
android:layout_gravity="center_horizontal|bottom"
- android:layout_marginStart="@dimen/controls_app_divider_side_margin"
- android:layout_marginEnd="@dimen/controls_app_divider_side_margin"
android:background="?android:attr/listDivider" />
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index e7bb3af..477a70f 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -98,15 +98,15 @@
<CheckBox
android:id="@+id/favorite"
android:visibility="invisible"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"
+ android:layout_width="@dimen/controls_management_checkbox_size"
+ android:layout_height="@dimen/controls_management_checkbox_size"
+ android:minHeight="0dp"
+ android:minWidth="0dp"
+ android:gravity="center"
android:background="@android:color/transparent"
android:clickable="false"
android:selectable="false"
android:importantForAccessibility="no"
- android:layout_marginTop="4dp"
- android:layout_marginStart="4dp"
app:layout_constraintStart_toEndOf="@id/subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml
index d1ce10e..d61122f 100644
--- a/packages/SystemUI/res/layout/controls_detail_dialog.xml
+++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml
@@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_marginBottom="10dp">
+ android:layout_marginBottom="4dp">
<ImageView
android:id="@+id/control_detail_close"
android:contentDescription="@string/accessibility_desc_close"
@@ -55,10 +55,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:paddingTop="@dimen/controls_activity_view_top_padding"
- android:paddingLeft="@dimen/controls_activity_view_side_padding"
- android:paddingRight="@dimen/controls_activity_view_side_padding"
- android:background="@drawable/rounded_bg_top"
+ android:background="@android:color/black"
android:orientation="vertical" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_dialog.xml b/packages/SystemUI/res/layout/controls_dialog.xml
index 3effaf5..5ce9916 100644
--- a/packages/SystemUI/res/layout/controls_dialog.xml
+++ b/packages/SystemUI/res/layout/controls_dialog.xml
@@ -18,8 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/controls_dialog_padding"
- android:layout_margin="@dimen/controls_dialog_padding"
>
<include
diff --git a/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml
index 90b3398..11144f6 100644
--- a/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml
+++ b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml
@@ -22,23 +22,17 @@
>
<View
- android:layout_width="match_parent"
- android:layout_height="@dimen/controls_management_list_margin"
- />
-
- <FrameLayout
android:id="@+id/frame"
android:layout_width="match_parent"
android:layout_height="@dimen/control_height"
android:visibility="gone"
>
- </FrameLayout>
+ </View>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
- android:layout_marginBottom="10dp"
- android:layout_marginStart="40dp"
- android:layout_marginEnd="40dp"
+ android:layout_marginBottom="@dimen/controls_management_editing_divider_margin"
+ android:layout_marginTop="@dimen/controls_management_editing_divider_margin"
android:background="#4dffffff" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index 835e54e..46f79de 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -31,18 +31,15 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="@dimen/controls_title_size"
+ android:textAppearance="@style/TextAppearance.Control.Management.Title"
android:textAlignment="center" />
-
-
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/controls_management_titles_margin"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.Control.Management.Subtitle"
android:textAlignment="center" />
<ViewStub
@@ -53,7 +50,7 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="64dp">
+ android:layout_height="72dp">
<View
android:layout_width="match_parent"
@@ -64,7 +61,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="4dp">
+ android:padding="@dimen/controls_management_footer_side_margin">
<Button
android:id="@+id/other_apps"
diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml
index 94df9d8..4348ffe 100644
--- a/packages/SystemUI/res/layout/controls_management_apps.xml
+++ b/packages/SystemUI/res/layout/controls_management_apps.xml
@@ -19,6 +19,8 @@
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="@dimen/controls_management_list_margin"
+ android:layout_marginTop="@dimen/controls_management_apps_list_margin"
+ android:layout_marginStart="@dimen/controls_management_apps_extra_side_margin"
+ android:layout_marginEnd="@dimen/controls_management_apps_extra_side_margin"
/>
diff --git a/packages/SystemUI/res/layout/controls_management_editing.xml b/packages/SystemUI/res/layout/controls_management_editing.xml
index 8a14ec3..7356b290 100644
--- a/packages/SystemUI/res/layout/controls_management_editing.xml
+++ b/packages/SystemUI/res/layout/controls_management_editing.xml
@@ -22,6 +22,6 @@
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingTop="@dimen/controls_management_list_margin"
+ android:paddingTop="@dimen/controls_management_editing_list_margin"
/>
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index d2ccfcb..a0d8ae4 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -32,10 +32,10 @@
<com.android.systemui.controls.management.ManagementPageIndicator
android:id="@+id/structure_page_indicator"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/controls_management_page_indicator_height"
android:layout_gravity="center"
android:layout_marginTop="@dimen/controls_management_list_margin"
- android:visibility="gone" />
+ android:visibility="invisible" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/structure_pager"
diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml
index 549874a..f24850e 100644
--- a/packages/SystemUI/res/layout/controls_more_item.xml
+++ b/packages/SystemUI/res/layout/controls_more_item.xml
@@ -18,6 +18,5 @@
style="@style/Control.MenuItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="24dp"
android:layout_gravity="start" />
diff --git a/packages/SystemUI/res/layout/controls_spinner_item.xml b/packages/SystemUI/res/layout/controls_spinner_item.xml
index 45540f1..574aed6 100644
--- a/packages/SystemUI/res/layout/controls_spinner_item.xml
+++ b/packages/SystemUI/res/layout/controls_spinner_item.xml
@@ -17,7 +17,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="8dp">
+ android:paddingVertical="@dimen/control_spinner_padding_vertical"
+ android:paddingHorizontal="@dimen/control_spinner_padding_horizontal">
<LinearLayout
android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
index 047ab98..f048d62 100644
--- a/packages/SystemUI/res/layout/controls_structure_page.xml
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -21,4 +21,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_list_margin"/>
\ No newline at end of file
+ android:layout_marginTop="@dimen/controls_management_zone_top_margin"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
index b323209..065ff68 100644
--- a/packages/SystemUI/res/layout/controls_with_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -21,14 +21,14 @@
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginTop="@dimen/controls_top_margin"
- android:layout_marginEnd="@dimen/controls_header_side_margin"
- android:layout_marginStart="@dimen/controls_header_side_margin">
+ android:layout_marginBottom="@dimen/controls_header_bottom_margin">
<!-- make sure the header stays centered in the layout by adding a spacer -->
<Space
android:layout_width="@dimen/controls_header_menu_size"
android:layout_height="1dp" />
-
+ <!-- need to keep this outer view in order to have a correctly sized anchor
+ for the dropdown menu, as well as dropdown background in the right place -->
<LinearLayout
android:id="@+id/controls_header"
android:orientation="horizontal"
@@ -38,15 +38,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center">
-
- <ImageView
- android:id="@+id/app_icon"
- android:layout_gravity="center"
- android:layout_width="@dimen/controls_header_app_icon_size"
- android:layout_height="@dimen/controls_header_app_icon_size"
- android:contentDescription="@null"
- android:layout_marginEnd="10dp" />
-
<TextView
style="@style/Control.Spinner.Header"
android:clickable="false"
@@ -55,7 +46,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
-
<ImageView
android:id="@+id/controls_more"
android:src="@drawable/ic_more_vert"
@@ -73,7 +63,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="30dp"
android:layout_marginLeft="@dimen/global_actions_side_margin"
android:layout_marginRight="@dimen/global_actions_side_margin" />
</merge>
diff --git a/packages/SystemUI/res/layout/controls_zone_header.xml b/packages/SystemUI/res/layout/controls_zone_header.xml
index 93f99b1..74c020a 100644
--- a/packages/SystemUI/res/layout/controls_zone_header.xml
+++ b/packages/SystemUI/res/layout/controls_zone_header.xml
@@ -18,10 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.Control.Title"
- android:layout_marginStart="12dp"
- android:layout_marginEnd="2dp"
- android:layout_marginTop="8dp"
+ android:textAppearance="@style/TextAppearance.Control.Management.Subtitle"
+ android:layout_marginTop="@dimen/controls_management_zone_top_margin"
android:layout_marginBottom="4dp">
-
</TextView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index fb57b47..e4e9d29 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -20,8 +20,6 @@
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
- android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
android:paddingTop="@dimen/global_actions_grid_vertical_padding"
android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 94a6bc5..1dbb38d 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -14,60 +14,89 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/global_screenshot_background"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="@android:color/black"
- android:visibility="gone"/>
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/global_screenshot_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<ImageView
android:id="@+id/global_screenshot_actions_background"
- android:layout_height="400dp"
+ android:layout_height="@dimen/screenshot_bg_protection_height"
android:layout_width="match_parent"
- android:layout_gravity="bottom|center"
+ android:alpha="0.0"
android:src="@drawable/screenshot_actions_background_protection"
- android:alpha="0"/>
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+ <ImageView
+ android:id="@+id/global_screenshot_actions_container_background"
+ android:visibility="gone"
+ android:layout_height="0dp"
+ android:layout_width="0dp"
+ android:elevation="1dp"
+ android:background="@drawable/action_chip_container_background"
+ android:layout_marginStart="@dimen/screenshot_action_container_margin_horizontal"
+ app:layout_constraintBottom_toBottomOf="@+id/global_screenshot_actions_container"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/global_screenshot_actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/global_screenshot_actions_container"/>
<HorizontalScrollView
android:id="@+id/global_screenshot_actions_container"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|left"
- android:elevation="1dp"
- android:fillViewport="true"
- android:layout_marginHorizontal="@dimen/screenshot_action_container_margin_horizontal"
+ android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
android:layout_marginBottom="@dimen/screenshot_action_container_offset_y"
- android:gravity="center"
- android:paddingLeft="@dimen/screenshot_action_container_padding_left"
- android:paddingRight="@dimen/screenshot_action_container_padding_right"
+ android:paddingHorizontal="@dimen/screenshot_action_container_padding_right"
android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
- android:visibility="gone"
+ android:elevation="1dp"
android:scrollbars="none"
- android:background="@drawable/action_chip_container_background">
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintWidth_percent="1.0"
+ app:layout_constraintWidth_max="wrap"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview"
+ app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:id="@+id/global_screenshot_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</HorizontalScrollView>
<ImageView
- android:id="@+id/global_screenshot"
- android:layout_width="wrap_content"
+ android:id="@+id/global_screenshot_animated_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:visibility="gone"
+ android:elevation="@dimen/screenshot_preview_elevation"
+ android:background="@drawable/screenshot_rounded_corners"
+ android:adjustViewBounds="true"/>
+ <ImageView
+ android:id="@+id/global_screenshot_preview"
+ android:layout_width="@dimen/global_screenshot_x_scale"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:layout_marginStart="@dimen/screenshot_offset_x"
+ android:layout_marginBottom="@dimen/screenshot_offset_y"
+ android:scaleType="fitEnd"
android:elevation="@dimen/screenshot_preview_elevation"
android:visibility="gone"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_preview_description"/>
+ android:contentDescription="@string/screenshot_preview_description"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
android:elevation="7dp"
android:visibility="gone"
- android:contentDescription="@string/screenshot_dismiss_ui_description">
+ android:contentDescription="@string/screenshot_dismiss_ui_description"
+ app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview"
+ app:layout_constraintEnd_toEndOf="@+id/global_screenshot_preview"
+ app:layout_constraintTop_toTopOf="@+id/global_screenshot_preview"
+ app:layout_constraintBottom_toTopOf="@+id/global_screenshot_preview">
<ImageView
android:id="@+id/global_screenshot_dismiss_image"
android:layout_width="match_parent"
@@ -79,14 +108,13 @@
android:id="@+id/global_screenshot_flash"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:src="@android:color/white"
+ android:visibility="gone"
android:elevation="@dimen/screenshot_preview_elevation"
- android:visibility="gone"/>
+ android:src="@android:color/white"/>
<com.android.systemui.screenshot.ScreenshotSelectorView
android:id="@+id/global_screenshot_selector"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:pointerIcon="crosshair"/>
-
-</FrameLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index bd91ddb..e4ae7c1 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -19,11 +19,11 @@
android:id="@+id/global_screenshot_action_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/screenshot_action_chip_margin_right"
+ android:layout_marginEnd="@dimen/screenshot_action_chip_margin_right"
android:layout_gravity="center"
android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
android:background="@drawable/action_chip_background"
- android:alpha="0"
+ android:alpha="0.0"
android:gravity="center">
<ImageView
android:id="@+id/screenshot_action_chip_icon"
diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
index e6f2790..21a671c 100644
--- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
@@ -47,14 +47,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
-
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
/>
<TextView
android:id="@+id/conversation_notification_sender"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
style="?attr/hybridNotificationTextStyle"
diff --git a/packages/SystemUI/res/layout/keyguard_media_header.xml b/packages/SystemUI/res/layout/keyguard_media_header.xml
index de9ef21..20ec10c 100644
--- a/packages/SystemUI/res/layout/keyguard_media_header.xml
+++ b/packages/SystemUI/res/layout/keyguard_media_header.xml
@@ -124,7 +124,7 @@
android:layout_gravity="center"
>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
@@ -132,7 +132,7 @@
android:id="@+id/action0"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
@@ -140,7 +140,7 @@
android:id="@+id/action1"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 66c0c5c..416ee81 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -30,6 +30,7 @@
android:id="@+id/status_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:paddingTop="@dimen/status_bar_padding_top"
android:layout_alignParentEnd="true"
android:gravity="center_vertical|end" >
<FrameLayout android:id="@+id/system_icons_container"
@@ -66,6 +67,7 @@
android:id="@+id/keyguard_carrier_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingTop="@dimen/status_bar_padding_top"
android:layout_marginStart="@dimen/keyguard_carrier_text_margin"
android:layout_toStartOf="@id/system_icons_container"
android:gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index ccb4f78..c27b3a9 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -30,7 +30,6 @@
android:layout_width="@dimen/qs_panel_width"
android:layout_height="wrap_content"
android:paddingTop="16dp"
- android:paddingBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:orientation="vertical"
@@ -44,7 +43,10 @@
android:id="@+id/show_at_top_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="horizontal"
>
<ImageView
@@ -58,13 +60,13 @@
<TextView
android:id="@+id/show_at_top_text"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical|start"
android:textSize="15sp"
android:ellipsize="end"
- android:maxLines="1"
+ android:maxLines="2"
android:text="@string/priority_onboarding_show_at_top_text"
style="@style/TextAppearance.NotificationInfo"
/>
@@ -75,7 +77,10 @@
android:id="@+id/show_avatar_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="horizontal"
>
<ImageView
@@ -89,13 +94,13 @@
<TextView
android:id="@+id/avatar_text"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical|start"
android:textSize="15sp"
android:ellipsize="end"
- android:maxLines="1"
+ android:maxLines="2"
android:text="@string/priority_onboarding_show_avatar_text"
style="@style/TextAppearance.NotificationInfo"
/>
@@ -108,7 +113,10 @@
android:id="@+id/floating_bubble_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="horizontal"
>
@@ -123,13 +131,13 @@
<TextView
android:id="@+id/bubble_text"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical|start"
android:textSize="15sp"
android:ellipsize="end"
- android:maxLines="1"
+ android:maxLines="2"
android:text="@string/priority_onboarding_appear_as_bubble_text"
style="@style/TextAppearance.NotificationInfo"
/>
@@ -140,7 +148,10 @@
android:id="@+id/ignore_dnd_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="horizontal"
>
@@ -155,13 +166,13 @@
<TextView
android:id="@+id/dnd_text"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical|start"
android:textSize="15sp"
android:ellipsize="end"
- android:maxLines="1"
+ android:maxLines="2"
android:text="@string/priority_onboarding_ignores_dnd_text"
style="@style/TextAppearance.NotificationInfo"
/>
@@ -173,7 +184,8 @@
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="4dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="horizontal"
>
<TextView
diff --git a/packages/SystemUI/res/layout/qqs_media_panel.xml b/packages/SystemUI/res/layout/qqs_media_panel.xml
index 403b5dc..2e86732 100644
--- a/packages/SystemUI/res/layout/qqs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qqs_media_panel.xml
@@ -63,7 +63,7 @@
android:gravity="center"
>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
@@ -71,7 +71,7 @@
android:id="@+id/action0"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
@@ -79,7 +79,7 @@
android:id="@+id/action1"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
index a194569..d633ff4 100644
--- a/packages/SystemUI/res/layout/qs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -197,7 +197,7 @@
android:gravity="center"
>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
@@ -207,7 +207,7 @@
android:id="@+id/action0"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
@@ -217,7 +217,7 @@
android:id="@+id/action1"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginStart="8dp"
@@ -227,7 +227,7 @@
android:id="@+id/action2"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
@@ -237,7 +237,7 @@
android:id="@+id/action3"
/>
<ImageButton
- style="@android:style/Widget.Material.Button.Borderless.Small"
+ style="@style/MediaPlayer.Button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 8676767..b27d096 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -26,7 +26,8 @@
android:orientation="horizontal"
android:clickable="true"
android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end" >
+ android:paddingEnd="@dimen/status_bar_padding_end"
+ android:paddingTop="@dimen/status_bar_padding_top" >
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index df576d8..fd9936f 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -59,29 +59,16 @@
android:layout_gravity="center"
android:layout_weight="0"
android:layout_marginRight="@dimen/screenrecord_dialog_padding"/>
- <LinearLayout
+ <Spinner
+ android:id="@+id/screen_recording_options"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_weight="1">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:text="@string/screenrecord_audio_label"
- android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/audio_type"
- android:text="@string/screenrecord_mic_label"
- android:textAppearance="?android:attr/textAppearanceSmall"/>
- </LinearLayout>
+ android:layout_height="48dp"
+ android:prompt="@string/screenrecord_audio_label"/>
<Switch
android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_weight="0"
+ android:layout_weight="1"
+ android:layout_gravity="end"
android:id="@+id/screenrecord_audio_switch"/>
</LinearLayout>
@@ -102,7 +89,8 @@
android:id="@+id/screenrecord_taps_switch"
android:text="@string/screenrecord_taps_label"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
new file mode 100644
index 0000000..af6f9bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:orientation="vertical"
+ android:padding="10dp"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"/>
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml
new file mode 100644
index 0000000..fabe9e2
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source_selected.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/screenrecord_audio_label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"/>
+ <TextView
+ android:id="@+id/screen_recording_dialog_source_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index dc070cb..d322e09 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -44,14 +44,6 @@
</com.android.systemui.statusbar.BackDropView>
<com.android.systemui.statusbar.ScrimView
- android:id="@+id/scrim_for_bubble"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:importantForAccessibility="no"
- sysui:ignoreRightInset="true"
- />
-
- <com.android.systemui.statusbar.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 6fb5590..818d1d7 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -26,7 +26,6 @@
android:layout_weight="1"
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding"
- android:paddingTop="@dimen/status_bar_padding_top"
android:gravity="center_vertical"
android:orientation="horizontal"/>
@@ -36,4 +35,4 @@
android:clipToPadding="false"
android:clipChildren="false"
systemui:textAppearance="@style/TextAppearance.StatusBar.Clock" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 73b293f..b393d21 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Kennisgewing is toegemaak."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Borrel is toegemaak."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kennisgewingskerm."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Vinnige instellings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sluitskerm."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skermopname"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Begin"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Toestel"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swiep op om programme te wissel"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep regs om programme vinnig te wissel"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Wissel oorsig"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Verskyn boaan die gespreksafdeling en lyk soos \'n borrel."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekspesifieke-instellings nie"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen onlangse borrels nie"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Kies kontroles om toegang vanaf die aan/af-kieslys te kry"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hou en sleep om kontroles te herrangskik"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle kontroles is verwyder"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Veranderinge is nie gestoor nie"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Die lys met alle kontroles kon nie gelaai word nie."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Voeg by toestelkontroles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index bc27119..195000e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ማሳወቂያ ተወግዷል።"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"አረፋ ተሰናብቷል።"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"የማሳወቂያ ጥላ።"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ፈጣን ቅንብሮች።"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ማያ ገጽ ቆልፍ።"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ከኃይል ምናሌ ላይ ለመድረስ መቆጣጠሪያዎችን ይምረጡ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"መቆጣጠሪያዎችን ዳግም ለማስተካከል ይያዙ እና ይጎትቱ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ሁሉም መቆጣጠሪያዎች ተወግደዋል"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ለውጦች አልተቀመጡም"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"የሁሉም መቆጣጠሪያዎች ዝርዝር ሊጫን አልተቻለም።"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ወደ የመሣሪያ መቆጣጠሪያዎች ያክሉ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 564ba0d..9cc6ec3 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"تم تجاهل الإشعار."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"تم إغلاق الفقاعة."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string>
@@ -438,8 +439,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"تسجيل الشاشة"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"بدء"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"إيقاف"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"الجهاز"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"مرّر سريعًا لأعلى لتبديل التطبيقات"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"اسحب لليسار للتبديل السريع بين التطبيقات"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تبديل \"النظرة العامة\""</string>
@@ -726,8 +726,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"تظهر كفقاعة محادثة في أعلى قسم المحادثات"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الإعدادات الخاصة بالمحادثة."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات محادثات"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
@@ -1052,8 +1051,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"اختيار عناصر التحكّم التي تريد الوصول إليها من قائمة التشغيل"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"اضغط مع الاستمرار واسحب لإعادة ترتيب عناصر التحكّم."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"تمت إزالة كل عناصر التحكّم."</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"لم يتم حفظ التغييرات."</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تعذّر تحميل قائمة كل عناصر التحكّم."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"إضافة إلى أدوات التحكم بالجهاز"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d9f8b77..6957e20 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"জাননী অগ্ৰাহ্য কৰা হৈছে।"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিংসমূহ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীণ।"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্ৰীন ৰেকর্ড"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"আৰম্ভ কৰক"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ কৰক"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইচ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"খৰতকীয়াকৈ আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ সোঁফালে টানক"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"বাৰ্তালাপ শাখাটোৰ শীৰ্ষত দেখুৱায় আৰু এটা বাবল হিচাপে প্ৰদর্শন হয়।"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপ নিৰ্দিষ্ট ছেটিংসমূহ সমৰ্থন নকৰে"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া bubbles নাই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"পাৱাৰ মেনুখনৰ পৰা এক্সেছ পাবলৈ নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"নিয়ন্ত্ৰণসমূহ পুনৰ সজাবলৈ ধৰি ৰাখক আৰু টানি আনি এৰক"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"সকলো নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"সালসলনিসমূহ ছেভ নহ’ল"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"নিয়ন্ত্ৰণসমূহৰ সম্পূর্ণ সূচীখন ল’ড কৰিব পৰা নগ’ল।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহত যোগ দিয়ক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 50d4953..2714811 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Bildiriş uzaqlaşdırıldı."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Qabarcıqdan imtina edilib."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildiriş kölgəsi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tez ayarlar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekranı kilidləyin."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran yazması"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlayın"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dayandırın"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Tətbiqi dəyişmək üçün yuxarı sürüşdürün"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tətbiqləri cəld dəyişmək üçün sağa çəkin"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"İcmala Keçin"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Söhbət bölməsinin yuxarısında göstərilir və yumrucuq kimi görünür."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbətə aid ayarları dəstəkləmir"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Yumrucuqlar yoxdur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Enerji menyusundan daxil olacağınız nizamlayıcıları seçin"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Nizamlayıcıları yenidən tənzimləmək üçün tutub sürüşdürün"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Bütün nizamlayıcılar silindi"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Dəyişikliklər yadda saxlanmadı"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Bütün nizamlayıcıların siyahısı yüklənmədi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz idarəetmələrinə əlavə edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index d290521..a7491777 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Dozvoli"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Otklanjanje grešaka na USB-u nije dozvoljeno"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može da uključi otklanjanje grešaka na USB-u. Da biste koristili ovu funkciju, prebacite na primarnog korisnika."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Želite li da omogućite bežično otklanjanje grešaka na ovoj mreži?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Želite da omogućite bežično otklanjanje grešaka na ovoj mreži?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi adresa (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Uvek dozvoli na ovoj mreži"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Dozvoli"</string>
@@ -162,12 +162,12 @@
<string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo ovog korisnika."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo ovog korisnika."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo ovog korisnika."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo profil za Work i njegove podatke."</string>
- <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo profil za Work i njegove podatke."</string>
- <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo profil za Work i njegove podatke."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
+ <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše netačnih pokušaja. Izbrisaćemo podatke sa ovog uređaja."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše netačnih pokušaja. Izbrisaćemo ovog korisnika."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netačnih pokušaja. Izbrisaćemo ovaj profil za Work i njegove podatke."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netačnih pokušaja. Izbrisaćemo ovaj poslovni profil i njegove podatke."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obaveštenje je odbačeno."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić je odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Prozor sa obaveštenjima."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brza podešavanja."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string>
@@ -414,7 +415,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Iskoristili ste <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Profil za Work"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Poslovni profil"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Noćno svetlo"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Uključuje se po zalasku sunca"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do izlaska sunca"</string>
@@ -529,11 +530,11 @@
<string name="quick_settings_disclosure_named_management" msgid="586473803771171610">"Ovim uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_management_vpns" msgid="3447553497516286109">"Uređajem upravlja organizacija i povezan je sa VPN-ovima"</string>
<string name="quick_settings_disclosure_named_management_vpns" msgid="4066586579688193212">"Uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> i povezan je sa VPN-ovima"</string>
- <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Organizacija može da prati mrežni saobraćaj na profilu za Work"</string>
- <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> može da nadgleda mrežni saobraćaj na profilu za Work"</string>
+ <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Organizacija može da prati mrežni saobraćaj na poslovnom profilu"</string>
+ <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> može da nadgleda mrežni saobraćaj na poslovnom profilu"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Mreža se možda nadgleda"</string>
<string name="quick_settings_disclosure_vpns" msgid="2890510056934492407">"Uređaj je povezan sa VPN-ovima"</string>
- <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="5149334449426566152">"Profil za Work je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="5149334449426566152">"Poslovni profil je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="4201831495800021670">"Lični profil je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_named_vpn" msgid="5069088739435424666">"Uređaj je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="monitoring_title_device_owned" msgid="7029691083837606324">"Upravljanje uređajima"</string>
@@ -548,12 +549,12 @@
<string name="monitoring_description_named_management" msgid="7424612629468754552">"Uređajem upravlja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nViše informacija potražite od administratora."</string>
<string name="monitoring_description_management" msgid="8081910434889677718">"Uređajem upravlja organizacija.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nViše informacija potražite od administratora."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizacija je na ovom uređaju instalirala autoritet za izdavanje sertifikata. Bezbedni mrežni saobraćaj može da se prati ili menja."</string>
- <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Organizacija je na profilu za Work instalirala autoritet za izdavanje sertifikata. Bezbedni mrežni saobraćaj može da se prati ili menja."</string>
+ <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Organizacija je na poslovnom profilu instalirala autoritet za izdavanje sertifikata. Bezbedni mrežni saobraćaj može da se prati ili menja."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Na ovom uređaju je instaliran autoritet za izdavanje sertifikata. Bezbedni mrežni saobraćaj može da se prati ili menja."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator je uključio evidentiranje mreže, koje prati saobraćaj na uređaju."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Povezani ste sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Povezani ste sa aplikacijama <xliff:g id="VPN_APP_0">%1$s</xliff:g> i <xliff:g id="VPN_APP_1">%2$s</xliff:g>, koje mogu da nadgledaju aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Profil za Work je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Poslovni profil je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Lični profil je povezan sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Uređajem upravlja <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> koristi <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje uređajem."</string>
@@ -567,13 +568,13 @@
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Otvorite pouzdane akreditive"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator je uključio evidentiranje mreže, koje prati saobraćaj na uređaju.\n\nKontaktirajte administratora za više informacija."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Dali ste dozvolu aplikaciji da podešava VPN vezu.\n\nTa aplikacija može da nadgleda aktivnosti na uređaju i mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> upravlja profilom za Work.\n\nAdministrator može da prati aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nKontaktirajte administratora za više informacija.\n\nPovezani ste i sa VPN-om, koji može da prati aktivnosti na mreži."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> upravlja poslovnim profilom.\n\nAdministrator može da prati aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nKontaktirajte administratora za više informacija.\n\nPovezani ste i sa VPN-om, koji može da prati aktivnosti na mreži."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
<string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"Poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent sprečava zaključavanje"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -651,7 +652,7 @@
<string name="show_demo_mode" msgid="3677956462273059726">"Prikaži režim demonstracije"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"Eternet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
- <string name="status_bar_work" msgid="5238641949837091056">"Profil za Work"</string>
+ <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodaj pločicu"</string>
<string name="broadcast_tile" msgid="5224010633596487481">"Pločica za emitovanje"</string>
@@ -661,7 +662,7 @@
<string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Brza podešavanja, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Hotspot"</string>
- <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil za Work"</string>
+ <string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Tjuner za korisnički interfejs sistema vam pruža dodatne načine za podešavanje i prilagođavanje Android korisničkog interfejsa. Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ca3f2db..6de1736 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Апавяшчэнне прапушчана."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Усплывальнае апавяшчэнне адхілена."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Цень апавяшчэння.."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Хуткія налады."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блакіроўкі."</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запіс экрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Прылада"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Правядзіце ўверх, каб пераключыць праграмы"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Каб хутка пераключыцца паміж праграмамі, перацягніце ўправа"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Уключыць/выключыць агляд"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Паказваецца ўверсе раздзела размоў у выглядзе ўсплывальнага апавяшчэння."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае пэўныя налады размоў"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Выберыце элементы кіравання, да якіх вы хочаце мець доступ з меню сілкавання"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Каб змяніць парадак элементаў кіравання, утрымлівайце і перацягвайце іх"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Усе элементы кіравання выдалены"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Змяненні не захаваны"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не ўдалося загрузіць спіс усіх сродкаў кіравання."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Дадаць у элементы кіравання прыладай"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 7108f79..156fb0f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известието е отхвърлено."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Балончето е отхвърлено."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Падащ панел с известия."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Бързи настройки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заключване на екрана."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Избиране на контроли, които да са достъпни в менюто за захранване"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Задръжте и плъзнете, за да пренаредите контролите"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Всички контроли са премахнати"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Промените не са запазени"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Списъкът с всички контроли не бе зареден."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Добавяне към контролите за устройството"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index a2a8689..599bf63 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্রিন রেকর্ড"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"শুরু করুন"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ করুন"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইস"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"অন্য অ্যাপে যেতে উপরের দিকে সোয়াইপ করুন"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"একটি অ্যাপ ছেড়ে দ্রুত অন্য অ্যাপে যেতে ডান দিকে টেনে আনুন"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"\'এক নজরে\' বৈশিষ্ট্যটি চালু বা বন্ধ করুন"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"কথোপকথন বিভাগের উপরে বাবল হিসেবে দেখা যায়।"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে কথোপকথনের ক্ষেত্রে প্রযোজ্য সেটিংস কাজ করে না"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনও সাম্প্রতিক বাবল নেই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 91b19d7..6e7722d 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obavještenje je uklonjeno."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić je odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obavještenja sa sjenčenjem."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string>
@@ -718,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Prikazuje se na vrhu odjeljka za razgovor u vidu oblačića."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke karakteristične za razgovor"</string>
+ <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke za određeni razgovor"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
@@ -1034,8 +1035,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izaberite kontrole za pristup iz menija napajanja"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Držite i prevucite da preuredite kontrole"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Sve kontrole su uklonjene"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Promjene nisu sačuvane"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspjelo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cb4d215..bf8c113 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificació omesa."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"La bombolla s\'ha ignorat."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Àrea de notificacions"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuració ràpida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueig"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravació de pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Atura"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositiu"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Llisca cap amunt per canviar d\'aplicació"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrossega el dit cap a la dreta per canviar ràpidament d\'aplicació"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activa o desactiva Aplicacions recents"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Es mostra com a bombolla a la part superior de la secció de converses."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet opcions de configuració específiques de converses"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hi ha bombolles recents"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bombolles recents i les ignorades es mostraran aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Selecciona els controls per accedir-hi des del menú d\'engegada"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantén premut i arrossega per reorganitzar els controls"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"S\'han suprimit tots els controls"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Els canvis no s\'han desat"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No s\'ha pogut carregar la llista completa de controls."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Afegeix als controls de dispositius"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3b0f340..8bce8ec 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Oznámení je zavřeno."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bublina byla zavřena."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel oznámení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rychlé nastavení."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Obrazovka uzamčení"</string>
@@ -719,7 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Zobrazuje se v horní části sekce konverzace a má podobu bubliny."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje specifická nastavení pro konverzaci"</string>
+ <string name="no_shortcut" msgid="7176375126961212514">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavení specifická pro konverzaci"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žádné nedávné bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
@@ -1038,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte ovládací prvky, které budou zobrazeny v nabídce vypínače"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Ovládací prvky můžete uspořádat podržením a přetažením"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Všechny ovládací prvky byly odstraněny"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Změny nebyly uloženy"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Načtení seznamu všech ovládacích prvků se nezdařilo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Přidání ovládání zařízení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2bc0e25..1837073 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifikationen er annulleret."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Boblen blev lukket."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notifikationspanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kvikmenu."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskærm."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vælg, hvilke indstillinger der skal være i menuen for afbryderknappen"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Flyt rundt på styringselementer ved at holde dem nede og trække"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle styringselementerne blev fjernet"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ændringerne blev ikke gemt"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over styringselementer kunne ikke indlæses."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Føj til enhedsstyring"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3efafec..1f78537 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Benachrichtigung geschlossen"</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Bildschirmaufnahme"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Beenden"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Gerät"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Nach oben wischen, um Apps zu wechseln"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zum schnellen Wechseln der Apps nach rechts ziehen"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Übersicht ein-/ausblenden"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Wird oben im Bereich für Unterhaltungen als Bubble angezeigt."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine unterhaltungsspezifischen Einstellungen"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Keine kürzlich geschlossenen Bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
@@ -1007,7 +1007,7 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Oben im Bereich für Unterhaltungen anzeigen"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Oben im Bereich \"Unterhaltungen\" anzeigen"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Profilbild auf Sperrbildschirm anzeigen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Unverankertes Infofeld über anderen Apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Bitte nicht stören\" unterbrechen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index f9ac3f2..16cf78b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Η ειδοποίηση έχει απορριφθεί."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Η φούσκα παραβλέφθηκε."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Επιλέξτε τα στοιχεία ελέγχου στα οποία θα έχετε πρόσβαση από το μενού λειτουργίας."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Κρατήστε και σύρετε για αναδιάταξη των στοιχείων ελέγχου"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Όλα τα στοιχεία ελέγχου καταργήθηκαν"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Οι αλλαγές δεν αποθηκεύτηκαν"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ανεπιτυχής φόρτωση λίστας όλων των στοιχ. ελέγχου."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Προσθήκη στα στοιχεία ελέγχου συσκευής"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index bf276a9..296d974 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index fccdffe..4e85aad 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index bf276a9..296d974 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index bf276a9..296d974 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 74dfa34..69a226c 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 97ead2c..966d07a 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación ignorada"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Se descartó el cuadro."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra a la derecha para cambiar aplicaciones rápidamente"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ocultar o mostrar Recientes"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Aparece como una burbuja en la parte superior de la sección de la conversación."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite opciones de configuración específicas de conversaciones"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Elige los controles a los que quieres acceder desde el menú de encendido"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantén presionado y arrastra para reorganizar los controles"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Se quitaron todos los controles"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"No se guardaron los cambios"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Agregar a controles de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f1b2b37..1b5c32a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuración USB no permitida"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"El usuario con el que se ha iniciado sesión en este dispositivo no puede activar la depuración USB. Para utilizar esta función, inicia sesión con la cuenta de usuario principal."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"¿Quieres permitir la depuración inalámbrica en esta red?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"¿Permitir la depuración inalámbrica en esta red?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Nombre de la red (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nDirección Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir siempre en esta red"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Permitir"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación ignorada"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Burbuja cerrada."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ajustes rápidos"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabación de la pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicio"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de aplicación"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra hacia la derecha para cambiar rápidamente de aplicación"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Mostrar u ocultar aplicaciones recientes"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Aparece en la parte superior de la sección de una conversación en forma de burbuja."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con ajustes específicos de conversaciones"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Elige los controles a los que acceder desde el menú de encendido"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantén pulsado y arrastra un control para reubicarlo"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos los controles quitados"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"No se han guardado los cambios"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se ha podido cargar la lista de los controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Añadir a control de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6fe4bf2..4b911a9 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Märguandest on loobutud."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Mullist loobuti."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Märguande vari."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kiirseaded."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kuva lukustamine."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Valige toitemenüüs saadaolevad juhtelemendid"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Juhtnuppude ümberpaigutamiseks hoidke neid all ja lohistage"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Kõik juhtnupud eemaldati"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muudatusi ei salvestatud"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Seadmete juhtimisvidinate hulka lisamine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 30e4eec..930d571 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Jakinarazpena baztertu da."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Baztertu da globoa."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Jakinarazpenen panela."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ezarpen bizkorrak."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantaila blokeatzeko aukera."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Pantaila-grabaketa"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hasi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Gelditu"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Gailua"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Egin gora aplikazioa aldatzeko"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastatu eskuinera aplikazioa azkar aldatzeko"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aldatu ikuspegi orokorra"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Elkarrizketen atalaren goialdean agertzen da, burbuila gisa."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen elkarrizketen berariazko ezarpenik"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ez dago azkenaldiko burbuilarik"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Aukeratu itzaltzeko menutik atzitu nahi dituzun kontrolatzeko aukerak"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Kontrolatzeko aukerak antolatzeko, eduki itzazu sakatuta, eta arrastatu"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Kontrolatzeko aukera guztiak kendu dira"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ez dira gorde aldaketak"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Gehitu gailuak kontrolatzeko widgetetan"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index a65cc37..dab05e2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"اعلان ردشد."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ابزارک اعلان رد شد."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مجموعه اعلان."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"تنظیمات سریع."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"صفحه قفل."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"برای دسترسی از منوی روشن/خاموش، کنترلها را انتخاب کنید"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"برای تغییر دادن ترتیب کنترلها، آنها را نگه دارید و بکشید"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"همه کنترلها برداشته شدهاند"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"تغییرات ذخیره نشد"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"فهرست همه کنترلها را نمیتوان بارگیری کرد."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"افزودن به کنترلهای دستگاه"</string>
@@ -1048,7 +1048,7 @@
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"خطا، درحال تلاش مجدد…"</string>
<string name="controls_error_removed" msgid="6299213591234723805">"دستگاه برداشته شد"</string>
- <string name="controls_error_generic" msgid="352500456918362905">"وضعیت بارگیری نشد"</string>
+ <string name="controls_error_generic" msgid="352500456918362905">"وضعیت بار نشد"</string>
<string name="controls_error_failed" msgid="960228639198558525">"خطا، دوباره امتحان کنید"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"درحال انجام"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"برای دیدن کنترلهای جدید، دکمه روشن/خاموش را پایین نگه دارید"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 56a43cf..3efc0d8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Ilmoitus hylätty."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Kupla ohitettu."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ilmoitusalue."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Pika-asetukset."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lukitse näyttö."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Näytön tallentaminen"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Laite"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vaihda sovellusta pyyhkäisemällä ylös"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vaihda sovellusta nopeasti vetämällä oikealle"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Näytä/piilota viimeisimmät"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Näkyy keskusteluosion yläosassa kuplana"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskustelukohtaisia asetuksia"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia kuplia"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Valitse säätimet, joita käytetään virtavalikosta"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Järjestele säätimiä koskettamalla pitkään ja vetämällä"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Kaikki säätimet poistettu"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muutoksia ei tallennettu"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kaikkien säätimien luetteloa ei voitu ladata."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Lisää laitteiden hallintaan"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 9376fea..25f886d3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulle ignorée."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement d\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayez vers le haut pour changer d\'application"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Balayez l\'écran vers la droite pour changer rapidement d\'application"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Basculer l\'aperçu"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"S\'affiche en haut de la section des conversations sous forme de bulle."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorité"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les paramètres propres aux conversations"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Sélectionnez les commandes auxquelles vous souhaitez accéder à partir du menu de l\'interrupteur"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Maintenez le doigt sur l\'écran, puis glissez-le pour réorganiser les commandes"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été supprimées"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modifications non enregistrées"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de contrôle des appareils"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e6bc809..0c8bb93 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulle fermée."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement de l\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayer l\'écran vers le haut pour changer d\'application"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Déplacer vers la droite pour changer rapidement d\'application"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'aperçu"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"S\'affiche en haut de la section des conversations et apparaît sous forme de bulle."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les paramètres de conversation"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Sélectionnez les commandes auxquelles vous souhaitez accéder depuis le menu de démarrage"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Appuyer et faire glisser pour réorganiser les commandes"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été supprimées"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Les modifications n\'ont pas été enregistrées"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de contrôle des appareils"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index f9e65e3..de290e0 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación rexeitada"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ignorouse a burbulla."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel despregable"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravación da pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Deter"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Pasar o dedo cara arriba para cambiar de aplicación"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra cara á dereita para cambiar de aplicacións rapidamente"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activar/desactivar Visión xeral"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Móstrase na parte superior da sección da conversa en forma de burbulla."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite opcións de configuración específicas para conversas"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Non hai burbullas recentes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"As burbullas recentes e ignoradas aparecerán aquí."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolle os controis para acceder desde o menú de acendido"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Para reorganizar os controis, mantenos premidos e arrástraos"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Quitáronse todos os controis"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Non se gardaron os cambios"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Non se puido cargar a lista de todos os controis."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Engadir ao control de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b9b2372..afbe13b 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"સૂચના કાઢી નાખી."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ્સ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"સ્ક્રીન રેકૉર્ડ કરો"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"શરૂ કરો"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"રોકો"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ડિવાઇસ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ઍપ સ્વિચ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ઍપને ઝડપથી સ્વિચ કરવા માટે જમણે ખેંચો"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ઝલકને ટૉગલ કરો"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"વાતચીત વિભાગની ટોચ પર બતાવે છે અને બબલ તરીકે દેખાય છે."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીત માટેના ચોક્કસ સેટિંગને સપોર્ટ કરતી નથી"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"તાજેતરના કોઈ બબલ નથી"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
@@ -961,7 +961,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ખલેલ પાડશો નહીં એક ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ખલેલ પાડશો નહીં એક સ્વચાલિત નિયમ અથવા ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> સુધી"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"રાખો"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"બદલો"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ac89c0c..df76774 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -257,6 +257,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारिज की गई."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -432,8 +434,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रिकॉर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"शुरू करें"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोकें"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"डिवाइस"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ऐप्लिकेशन बदलने के लिए ऊपर स्वाइप करें"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ऐप्लिकेशन को झटपट स्विच करने के लिए उसे दाईं ओर खींचें और छोड़ें"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"खास जानकारी टॉगल करें"</string>
@@ -716,8 +717,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"यह बातचीत सेक्शन में सबसे ऊपर और एक बबल के तौर पर दिखती है."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> में हर बातचीत के लिए अलग सेटिंग तय नहीं की जा सकती"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 6e77cd1..488de5d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obavijest je odbačena."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon obavijesti."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključavanje zaslona."</string>
@@ -1032,8 +1033,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Odaberite kontrole kojima želite pristupati iz izbornika napajanja"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Zadržite i povucite da biste promijenili raspored kontrola"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Sve su kontrole uklonjene"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Promjene nisu spremljene"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Popis svih kontrola nije se učitao."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodavanje kontrolama uređaja"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 34cc36b..d44f837 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Értesítés elvetve."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Buborék elvetve."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Értesítési felület."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Gyorsbeállítások."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lezárási képernyő."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Képernyő rögzítése"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Kezdés"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Leállítás"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Eszköz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Váltás az alkalmazások között felfelé csúsztatással"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Húzza jobbra az ujját az alkalmazások közötti gyors váltáshoz"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Áttekintés be- és kikapcsolása"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"A beszélgetések szakaszának tetején, buborékként jelenik meg."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a beszélgetésspecifikus beállításokat"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nincsenek buborékok a közelmúltból"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"A bekapcsológomb menüjéből hozzáférhető vezérlők kiválasztása"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tartsa lenyomva, és húzza a vezérlők átrendezéséhez"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Minden vezérlő eltávolítva"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"A rendszer nem mentette a módosításokat"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nem sikerült betölteni az összes vezérlő listáját."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Hozzáadás az eszközvezérlőkhöz"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index a87761a..1ce80ff 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Ծանուցումը անտեսվեց:"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ամպիկը փակվեց։"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ծանուցումների վահանակ:"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Արագ կարգավորումներ:"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Էկրանի կողպում:"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Էկրանի ձայնագրում"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Սկսել"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Կանգնեցնել"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Սարք"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Սահեցրեք վերև՝ մյուս հավելվածին անցնելու համար"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Քաշեք աջ՝ հավելվածների միջև անցնելու համար"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Միացնել/անջատել համատեսքը"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Ցուցադրվում է «Խոսակցություններ» բաժնում և հայտնվում է ամպիկի տեսքով։"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում զրույցի կարգավորումները"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Վերջին ամպիկներ չկան"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Ընտրեք կառավարման տարրերը՝ դրանք սնուցման ընտրացանկից բացելու համար"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Պահեք և քաշեք՝ կառավարման տարրերը վերադասավորելու համար"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Կառավարման բոլոր տարրերը հեռացվեցին"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Փոփոխությունները չեն պահվել"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Չհաջողվեց բեռնել բոլոր կառավարների ցանկը։"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Ավելացրեք սարքերի կառավարման տարրերում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 82dd783..8f506952 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifikasi disingkirkan."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balon ditutup."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bayangan pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setelan cepat."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Layar kunci."</string>
@@ -434,7 +435,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Geser ke atas untuk beralih aplikasi"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tarik ke kanan untuk beralih aplikasi dengan cepat"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktifkan Ringkasan"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Terisi"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Terisi penuh"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Mengisi daya"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Tidak mengisi daya"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pilih kontrol yang akan diakses dari menu daya"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tahan & tarik untuk mengatur ulang kontrol"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Semua kontrol dihapus"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Perubahan tidak disimpan"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Daftar semua kontrol tidak dapat dimuat."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan ke kontrol perangkat"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 3762fac..c3e33fc 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Tilkynningu lokað."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Blöðru lokað."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Tilkynningasvæði."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Flýtistillingar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lásskjár."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skjáupptaka"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hefja"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stöðva"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Tæki"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Strjúktu upp til að skipta á milli forrita"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Dragðu til hægri til að skipta hratt á milli forrita"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kveikja/slökkva á yfirliti"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Sýnt sem blaðra efst í samtali."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki stillingar fyrir einstök samtöl"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Engar nýlegar blöðrur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Veldu hvaða stýringar birtast í aflrofavalmyndinni"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Haltu og dragðu til að endurraða stýringum"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Allar stýringar fjarlægðar"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Breytingar ekki vistaðar"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ekki tókst að hlaða lista yfir allar stýringar."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Bæta við tækjastjórnun"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3e34544..db33a9a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifica eliminata."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Fumetto ignorato."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Area notifiche."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Impostazioni rapide."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Schermata di blocco."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Seleziona i controlli a cui accedere dal menu di accensione"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tieni premuto e trascina per riordinare i controlli"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Tutti i controlli sono stati rimossi"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modifiche non salvate"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossibile caricare l\'elenco di tutti i controlli."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Aggiungi al controllo dei dispositivi"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 07e1c1c..f814e6b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"התראה נדחתה."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"הבועה נסגרה."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"לוח התראות."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"הגדרות מהירות."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"מסך נעילה."</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"הקלטת המסך"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"מכשיר"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"יש להחליק מעלה כדי להחליף אפליקציות"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"יש לגרור ימינה כדי לעבור במהירות בין אפליקציות"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"החלפת מצב של מסכים אחרונים"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"מוצגת בחלק העליון של קטע השיחה ומופיעה כבועה."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"עדיפות"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בהגדרות ספציפיות לשיחות"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"אין בועות מהזמן האחרון"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"יש לבחור פקדים לגישה מתפריט ההפעלה"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"יש ללחוץ לחיצה ארוכה ולגרור כדי לארגן מחדש את הפקדים"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"כל הפקדים הוסרו"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"השינויים לא נשמרו"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"לא ניתן היה לטעון את הרשימה של כל הפקדים."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"הוספה לפקדי המכשירים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7ced5fd..4b5394f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"通知が削除されました。"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ふきだしが非表示になっています。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知シェード"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"クイック設定"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ロック画面"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"電源メニューからアクセスするコントロールを選択する"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"コントロールを並べ替えるには長押ししてドラッグします"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"すべてのコントロールを削除しました"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"変更が保存されていません"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"全コントロールの一覧を読み込めませんでした。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"デバイス コントロールに追加"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 3198303..242ee8d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"შეტყობინება წაიშალა."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ბუშტი დაიხურა."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"შეტყობინებების ფარდა"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"სწრაფი პარამეტრები"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ეკრანის დაბლოკვა."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"აირჩიეთ მართვის საშუალებები ელკვების მენიუდან"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"მართვის საშუალებების გადაწყობა შეგიძლიათ მათი ჩავლებით გადატანით"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"მართვის ყველა საშუალება ამოიშალა"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ცვლილებები არ შენახულა"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"მართვის ყველა საშუალების სია ვერ ჩაიტვირთა."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"მოწყობილ. მართვის საშუალებებში დამატება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 537aa36..598b281 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -57,12 +57,12 @@
<string name="label_view" msgid="6815442985276363364">"Көрініс"</string>
<string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> қосылған кезде, <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасын ашу"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> қосылған кезде, <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасын ашу"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"USB жөндеуге рұқсат берілсін бе?"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"USB арқылы түзетуге рұқсат берілсін бе?"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"Бұл компьютердің RSA перне саусақ таңбасы:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Осы компьютерден әрқашан рұқсат беру"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Рұқсат беру"</string>
- <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB жөндеу рұқсат етілмеген"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Бұл құрылғыға жаңа кірген пайдаланушы USB түзетуін іске қосылмайды. Бұл мүмкіндікті пайдалану үшін негізгі пайдаланушыға ауысыңыз."</string>
+ <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB арқылы түзетуге рұқсат етілмеген"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Бұл құрылғыға қазір кірген пайдаланушы USB арқылы түзетуді іске қосылмайды. Бұл мүмкіндікті пайдалану үшін негізгі пайдаланушыға ауысыңыз."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Бұл желіде сымсыз түзетуге рұқсат етілсін бе?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Желі атауы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi мекенжайы (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Осы желіде үнемі рұқсат ету"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Хабар алынып тасталды."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Қалқымалы анықтама өшірілді."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Хабарландыру тақтасы"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Жылдам параметрлер."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Бекіту экраны."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жазу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Бастау"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Тоқтату"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Құрылғы"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Қолданбалар арасында ауысу үшін жоғары сырғытыңыз"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Қолданбаларды жылдам ауыстырып қосу үшін оңға қарай сүйреңіз"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Шолуды қосу/өшіру"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Сөйлесу бөлімінің жоғарғы жағында және қалқыма хабар түрінде көрсетіледі."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында чаттың арнайы параметрлеріне қолдау көрсетілмейді."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
@@ -753,7 +752,7 @@
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"Есіме салу"</string>
<string name="notification_menu_settings_action" msgid="7085494017202764285">"Параметрлер"</string>
<string name="snooze_undo" msgid="60890935148417175">"КЕРІ ҚАЙТАРУ"</string>
- <string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> кідіртілді"</string>
+ <string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> кейінге қалдырылды"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
<item quantity="other">%d сағат</item>
<item quantity="one">%d сағат</item>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"\"Қуат\" мәзірінен пайдалануға болатын басқару элементтерін таңдаңыз."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Басқару элементтерінің ретін өзгерту үшін оларды басып тұрып сүйреңіз."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Барлық басқару элементтері өшірілді."</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгерістер сақталмады."</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Барлық басқару элементі тізімі жүктелмеді."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару виджеттеріне қосу"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 97a1c36..fc13931 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"បានបដិសេធការជូនដំណឹង"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"បានច្រានចោលសារលេចឡើង។"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ពណ៌ការជូនដំណឹង"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ការកំណត់រហ័ស។"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ចាក់សោអេក្រង់។"</string>
@@ -713,7 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"បង្ហាញនៅខាងលើផ្នែកសន្ទនា និងបង្ហាញជាពពុះ។"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើការកំណត់ជាក់លាក់សម្រាប់ការសន្ទនាបានទេ"</string>
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើការកំណត់ជាក់លាក់ចំពោះការសន្ទនាបានទេ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមានពពុះថ្មីៗទេ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ពពុះថ្មីៗ និងពពុះដែលបានបិទនឹងបង្ហាញនៅទីនេះ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាចកែប្រែការជូនដំណឹងទាំងនេះបានទេ។"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ជ្រើសរើសការគ្រប់គ្រង ដើម្បីចូលប្រើពីម៉ឺនុយថាមពល"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ចុចឱ្យជាប់ រួចអូសដើម្បីរៀបចំការគ្រប់គ្រងឡើងវិញ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"បានលុបការគ្រប់គ្រងទាំងអស់ហើយ"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"មិនបានរក្សាទុកការផ្លាស់ប្ដូរទេ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាចផ្ទុកបញ្ជីនៃការគ្រប់គ្រងទាំងអស់បានទេ។"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"បញ្ចូលទៅក្នុងផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7fe7d46..4dd6814 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್ ಪರದೆ."</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ನಿಲ್ಲಿಸಿ"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ಸಾಧನ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಿಸಲು ತ್ವರಿತವಾಗಿ ಬಲಕ್ಕೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ಟಾಗಲ್ ನ ಅವಲೋಕನ"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಬಾಗದಲ್ಲಿ ಕಾಣಿಸುತ್ತದೆ ಮತ್ತು ಬಬಲ್ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಸಂಭಾಷಣೆ ನಿರ್ದಿಷ್ಟ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e27f208..a56bf4a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"알림이 제거되었습니다."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"대화창을 닫았습니다."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"알림 세부정보"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"빠른 설정"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"화면을 잠급니다."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"전원 메뉴에서 액세스할 컨트롤을 선택합니다."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"길게 누르고 드래그하여 컨트롤 재정렬"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"모든 컨트롤 삭제됨"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"변경사항이 저장되지 않음"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"기기 제어에 추가"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 93deca2..fda3a05 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Эскертме өчүрүлдү."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Калкып чыкма билдирме жабылды."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Билдирмелер тактасы."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Тез тууралоолор."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Кулпуланган экран."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жаздыруу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Түзмөк"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Башка колдонмого которулуу үчүн,, өйдө сүрүңүз"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Колдонмолорду тез которуштуруу үчүн, оңго сүйрөңүз"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Сереп салууну өчүрүү/күйгүзүү"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Жазышуу бөлүмүнүн жогорку жагында көрсөтүлүп, калкып чыкма билдирме катары пайда болот."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда жазышууга болбойт"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Акыркы калкып чыкма билдирмелер жок"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Кайра жөнөтүлгөн жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Күйгүзүү/өчүрүү баскычынын менюсу үчүн көзөмөлдөрдү тандаңыз"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Башкаруу элементтеринин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Бардык башкаруу элементтери өчүрүлдү"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгөртүүлөр сакталган жок"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Түзмөктү башкаруу элементтерине кошуу"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 38db899..1ff99d5 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -57,7 +57,7 @@
<string name="label_view" msgid="6815442985276363364">"ເບິ່ງ"</string>
<string name="always_use_device" msgid="210535878779644679">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ທຸກເທື່ອທີ່ເຊື່ອມຕໍ່ <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"ເປີດ <xliff:g id="APPLICATION">%1$s</xliff:g> ທຸກເທື່ອທີ່ເຊື່ອມຕໍ່ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"ອະນຸຍາດການດີບັ໊ກຜ່ານ USB?"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"ອະນຸຍາດການດີບັກຜ່ານ USB?"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"ລາຍນິ້ມື RSA ຂອງຄອມພິວເຕີແມ່ນ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"ອະນຸຍາດຈາກຄອມພິວເຕີນີ້ຕະຫຼອດ"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"ອະນຸຍາດ"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ໜ້າຈໍແຈ້ງເຕືອນ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ການຕັ້ງຄ່າດ່ວນ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ລັອກໜ້າຈໍ."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ເລືອກການຄວບຄຸມເພື່ອເຂົ້າເຖິງຈາກເມນູເປີດປິດ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ກົດຄ້າງໄວ້ເພື່ອຈັດຮຽງການຄວບຄຸມຄືນໃໝ່"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ລຶບການຄວບຄຸມທັງໝົດອອກແລ້ວ"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ບໍ່ໄດ້ບັນທຶກການປ່ຽນແປງໄວ້"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ບໍ່ສາມາດໂຫຼດລາຍຊື່ການຄວບຄຸມທັງໝົດໄດ້."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ເພີ່ມໃສ່ການຄວບຄຸມອຸປະກອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 277814f..fd75874 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Pranešimo atsisakyta."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Debesėlio atsisakyta."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pranešimų gaubtas."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Spartieji nustatymai."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Užrakinimo ekranas."</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrano įrašas"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Pradėti"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stabdyti"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Įrenginys"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Perbraukite aukštyn, kad perjungtumėte programas"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vilkite į dešinę, kad greitai perjungtumėte programas"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Perjungti apžvalgą"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Rodoma pokalbio skilties viršuje kaip burbulas."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko konkrečių pokalbių nustatymų"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulus bus rodomi čia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pasirinkite valdiklius, kuriuos norite pasiekti įjungimo meniu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Norėdami pertvarkyti valdiklius, vilkite laikydami nuspaudę"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Visi valdikliai pašalinti"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Pakeitimai neišsaugoti"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nepavyko įkelti visų valdiklių sąrašo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Pridėjimas prie įrenginio valdiklių"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 46df9b9..d708e5b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Paziņojums netiek rādīts."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Burbulis ir noraidīts."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Paziņojumu panelis"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ātrie iestatījumi"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Bloķēšanas ekrāns."</string>
@@ -432,8 +433,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrāna ierakstīšana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Sākt"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Apturēt"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Ierīce"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Velciet augšup, lai pārslēgtu lietotnes"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Lai ātri pārslēgtu lietotnes, velciet pa labi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pārskata pārslēgšana"</string>
@@ -717,8 +717,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Tiek rādīta sarunas sadaļas augšdaļā kā burbulis."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīti atsevišķu sarunu iestatījumi."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nav nesen aizvērtu burbuļu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
@@ -1034,8 +1033,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izvēlieties vadīklas, kurām piekļūt no barošanas izvēlnes"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Lai pārkārtotu vadīklas, turiet un velciet tās"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Visas vadīklas ir noņemtas"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Izmaiņas nav saglabātas."</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nevarēja ielādēt sarakstu ar visām vadīklām."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Pievienošana ierīču vadīklām"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index bf688ba..9012b41 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Балончето е отфрлено."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Изберете ги контролите до кои ќе пристапувате од менито за вклучување"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Задржете и влечете за да ги преуредите контролите"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Сите контроли се отстранети"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Промените не се зачувани"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не можеше да се вчита списокот со сите контроли."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друга"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Додајте во контроли за уредите"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index b4715ca..8581a65 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"അറിയിപ്പ് നിരസിച്ചു."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്ഡ്."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്ക്രീൻ."</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"സ്ക്രീൻ റെക്കോർഡ്"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ആരംഭിക്കുക"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"നിര്ത്തുക"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ഉപകരണം"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ആപ്പുകൾ മാറാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ആപ്പുകൾ പെട്ടെന്ന് മാറാൻ വലത്തോട്ട് വലിച്ചിടുക"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"അവലോകനം മാറ്റുക"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"സംഭാഷണ വിഭാഗത്തിന് മുകളിൽ ബബിളായി ദൃശ്യമാവുന്നു."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"സംഭാഷണ നിർദ്ദിഷ്ട ക്രമീകരണം <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
@@ -961,7 +961,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ഒരു ആപ്പ് (<xliff:g id="ID_1">%s</xliff:g>) \'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കിയിരിക്കുന്നു."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"സ്വയമേവയുള്ള ഒരു നയമോ ആപ്പോ \'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കിയിരിക്കുന്നു."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> വരെ"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"സൂക്ഷിക്കുക"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"മാറ്റിസ്ഥാപിക്കുക"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ബാറ്ററി, ഡാറ്റ ഉപയോഗം എന്നിവയുടെ വിശദാംശങ്ങളറിയാൻ ടാപ്പുചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index bf0b7c8..4a3a5cd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Мэдэгдэл хаагдсан."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Бөмбөлгийг үл хэрэгссэн."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Мэдэгдлийн хураангуй самбар"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Шуурхай тохиргоо."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Дэлгэц түгжих."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Тэжээлийн цэсээс хандах хяналтуудыг сонгоно уу"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Хяналтуудыг дахин засварлахын тулд дараад чирнэ үү"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Бүх хяналтыг хассан"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өөрчлөлтийг хадгалаагүй"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бүх хяналтын жагсаалтыг ачаалж чадсангүй."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Төхөөрөмжийн хяналт руу нэмэх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6868a7f..530dbfb 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना डिसमिस केल्या."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिंग्ज."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रेकॉर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरू"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"थांबा"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"डिव्हाइस"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"अॅप्स स्विच करण्यासाठी वर स्वाइप करा"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"अॅप्स वर झटपट स्विच करण्यासाठी उजवीकडे ड्रॅग करा"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"अवलोकन टॉगल करा."</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"संभाषण विभागाच्या सर्वात वरती दिसते आणि बबलसारखे दिसते."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> संभाषण विशिष्ट सेटिंग्जना सपोर्ट करत नाही"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"अलीकडील कोणतेही बबल नाहीत"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index baaccf3..482d608 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Pemberitahuan diketepikan."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Gelembung diketepikan."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kunci skrin."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rakam Skrin"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mula"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Peranti"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Leret ke atas untuk menukar apl"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Seret ke kanan untuk beralih apl dengan pantas"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Togol Ikhtisar"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Ditunjukkan di sebelah atas bahagian perbualan dan muncul sebagai gelembung."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Tetapan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan khusus perbualan"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tiada gelembung terbaharu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
@@ -966,7 +965,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apl yang berjalan di latar belakang"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Ketik untuk mendapatkan butiran tentang penggunaan kuasa bateri dan data"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Matikan data mudah alih?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tiada akses kepada data atau Internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya tersedia melaui Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tidak akan mempunyai akses kepada data atau Internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya tersedia melaui Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"pembawa anda"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Oleh sebab apl melindungi permintaan kebenaran, Tetapan tidak dapat mengesahkan jawapan anda."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Benarkan <xliff:g id="APP_0">%1$s</xliff:g> menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan?"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pilih kawalan untuk diakses daripada menu kuasa"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Tahan & seret untuk mengatur semula kawalan"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Semua kawalan dialih keluar"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Perubahan tidak disimpan"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Senarai semua kawalan tidak dapat dimuatkan."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan pada kawalan peranti"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 4a4e96ae..6366acb 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အကြောင်းကြားစာအကွက်"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ဖွင့်ပိတ်မီနူးမှ သုံးရန် ထိန်းချုပ်မှုများ ရွေးပါ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ထိန်းချုပ်မှုများ ပြန်စီစဉ်ရန် ဖိပြီးဆွဲပါ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ထိန်းချုပ်မှုအားလုံး ဖယ်ရှားလိုက်သည်"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"အပြောင်းအလဲများကို သိမ်းမထားပါ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ထိန်းချုပ်မှုအားလုံး၏ စာရင်းကို ဖွင့်၍မရပါ။"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"စက်ထိန်းစနစ်သို့ ထည့်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index dc749ec..3fd742e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Varselet ble skjult."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Boblen er avvist."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Varselskygge."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hurtiginnstillinger."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskjerm."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Velg kontroller som er tilgjengelige fra av/på-menyen"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold og dra for å flytte kontroller"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle kontroller er fjernet"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Endringene er ikke lagret"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over alle kontroller kunne ikke lastes inn."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Legg til i enhetsstyring"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 04fff85..6a9fb2a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारेज।"</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्रिनको रेकर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरु गर्नुहोस्"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोक्नुहोस्"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"यन्त्र"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"एपहरू बदल्न माथितिर स्वाइप गर्नुहोस्"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"एपहरू बदल्न द्रुत गतिमा दायाँतिर ड्र्याग गर्नुहोस्"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"वार्तालाप खण्डको सिरानमा बबलका रूपमा देखा पर्छ।"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापविशेषका लागि सेटिङ उपलब्ध छैन"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालैका बबलहरू छैनन्"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 2d51011..196357c 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -79,6 +79,7 @@
<color name="global_screenshot_button_icon">@color/GM2_blue_300</color>
<color name="global_screenshot_dismiss_background">@color/GM2_grey_800</color>
<color name="global_screenshot_dismiss_foreground">#FFFFFF</color>
+ <color name="global_screenshot_background_protection_start">#80000000</color> <!-- 50% black -->
<!-- Biometric dialog colors -->
diff --git a/packages/SystemUI/res/values-night/dimens.xml b/packages/SystemUI/res/values-night/dimens.xml
index 4814839..23e3231 100644
--- a/packages/SystemUI/res/values-night/dimens.xml
+++ b/packages/SystemUI/res/values-night/dimens.xml
@@ -18,4 +18,8 @@
<resources>
<!-- The height of the divider between the individual notifications. -->
<dimen name="notification_divider_height">1dp</dimen>
+
+ <!-- Height of the background gradient behind the screenshot UI (taller in dark mode) -->
+ <dimen name="screenshot_bg_protection_height">375dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7376861..25965136 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Melding verwijderd."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubbel gesloten."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelingsscherm."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Kies bedieningselementen die je vanaf het aan/uit-menu wilt kunnen gebruiken"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Houd vast en sleep om de bedieningselementen opnieuw in te delen"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle bedieningselementen verwijderd"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Wijzigingen zijn niet opgeslagen"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kan lijst met alle bedieningselementen niet laden."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Toevoegen aan apparaatbediening"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 08afd1f..f5e7f12 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -35,7 +35,7 @@
<string name="battery_low_why" msgid="2056750982959359863">"ସେଟିଂସ୍"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ବ୍ୟାଟେରୀ ସେଭର୍ ଚାଲୁ କରିବେ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ବ୍ୟାଟେରୀ ସେଭର୍ ବିଷୟରେ"</string>
- <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"ବ୍ୟାଟେରୀ ସେଭର୍ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"ସେଟିଂସ୍"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"ୱାଇ-ଫାଇ"</string>
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ଦ୍ରୁତ ସେଟିଂସ୍।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ସ୍କ୍ରିନ୍ ରେକର୍ଡ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ବନ୍ଦ କରନ୍ତୁ"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ଡିଭାଇସ୍"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ଆପ୍କୁ ବଦଳ କରିବା ପାଇଁ ସ୍ଵାଇପ୍ କରନ୍ତୁ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ଆପ୍ଗୁଡ଼ିକ ମଧ୍ୟରେ ଶୀଘ୍ର ବଦଳ କରିବା ପାଇଁ ଡାହାଣକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀକୁ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
@@ -675,7 +676,7 @@
<string name="experimental" msgid="3549865454812314826">"ପରୀକ୍ଷାମୂଳକ"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"ବ୍ଲୁଟୂଥ୍ ଅନ୍ କରିବେ?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"ଆପଣଙ୍କ ଟାବଲେଟ୍ରେ କୀ’ବୋର୍ଡ ସଂଯୋଗ କରିବା ପାଇଁ ଆପଣଙ୍କୁ ପ୍ରଥମେ ବ୍ଲୁଟୂଥ୍ ଅନ୍ କରିବାକୁ ହେବ।"</string>
- <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="show_silently" msgid="5629369640872236299">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ନିରବରେ ଦେଖାନ୍ତୁ"</string>
<string name="block" msgid="188483833983476566">"ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବ୍ଲକ୍ କରନ୍ତୁ"</string>
<string name="do_not_silence" msgid="4982217934250511227">"ନିରବ କରନ୍ତୁ ନାହିଁ"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"ଏହା ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ।"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ସମ୍ବନ୍ଧିତ ନିର୍ଦ୍ଦିଷ୍ଟ ସେଟିଂସକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
@@ -961,7 +961,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ଏକ ଆପ୍ (<xliff:g id="ID_1">%s</xliff:g>) ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରାଗଲା।"</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ଏକ ସ୍ୱଚାଳିତ ନିୟମ କିମ୍ବା ଆପ୍ ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରାଗଲା।"</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"ଧରି ରଖନ୍ତୁ"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"ବଦଳାନ୍ତୁ"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ବ୍ୟାକଗ୍ରାଉଣ୍ଡରେ ଆପ୍ ଚାଲୁଛି"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ବ୍ୟାଟେରୀ ଏବଂ ଡାଟା ବ୍ୟବହାର ଉପରେ ବିବରଣୀ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 60846c6..37cf38c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ਰੋਕੋ"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"ਡੀਵਾਈਸ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ਐਪਾਂ ਵਿਚਾਲੇ ਤੇਜ਼ੀ ਨਾਲ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ਰੂਪ-ਰੇਖਾ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਉੱਪਰ ਅਤੇ ਬਬਲ ਦੇ ਤੌਰ \'ਤੇ ਦਿਖਾਉਂਦਾ ਹੈ।"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ ਸੈਟਿੰਗਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"ਪਹੁੰਚ ਕਰਨ ਲਈ ਪਾਵਰ ਮੀਨੂ ਤੋਂ ਕੰਟਰੋਲ ਚੁਣੋ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ਕੰਟਰੋਲਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ਸਾਰੇ ਕੰਟਰੋਲ ਹਟਾਏ ਗਏ"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ਤਬਦੀਲੀਆਂ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ਸਾਰੇ ਕੰਟਰੋਲਾਂ ਦੀ ਸੂਚੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a18df6f..087ab50 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Zamknięto powiadomienie."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Zamknięto dymek"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obszar powiadomień."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Szybkie ustawienia."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekran blokady."</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Nagrywanie ekranu"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Urządzenie"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Przesuń w górę, by przełączyć aplikacje"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Szybko przeciągnij w prawo, by przełączyć aplikacje"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Przełącz Przegląd"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Wyświetla się u góry sekcji rozmów i ma postać dymku."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje ustawień rozmowy"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Brak ostatnich dymków"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Wybierz elementy sterujące dostępne w menu zasilania"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Przytrzymaj i przeciągnij, aby przestawić elementy sterujące"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Usunięto wszystkie elementy sterujące"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmiany nie zostały zapisane"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nie udało się wczytać listy elementów sterujących."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodaj do sterowania urządzeniami"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 6e97aa6..c22a277 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação dispensada."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão dispensado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantenha a tela pressionada e arraste para reorganizar os controles"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index cc2baad..cea04db 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -46,12 +46,12 @@
<string name="bluetooth_tethered" msgid="4171071193052799041">"Bluetooth ligado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"Configurar métodos introdução"</string>
<string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"Teclado físico"</string>
- <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
- <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
- <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
- <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
- <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
- <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que a app <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+ <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Permitir que a app <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Pretende abrir a app <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Pretende abrir a app <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+ <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Pretende abrir a app <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"Nenhuma das aplicações instaladas funciona com o acessório USB. Saiba mais acerca do acessório em <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"Acessório USB"</string>
<string name="label_view" msgid="6815442985276363364">"Ver"</string>
@@ -85,7 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"Não foi possível guardar a captura de ecrã"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Experimente voltar a efetuar a captura de ecrã."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Não é possível guardar a captura de ecrã devido a espaço de armazenamento limitado."</string>
- <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A aplicação ou a sua entidade não permitem tirar capturas de ecrã"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A app ou a sua entidade não permitem tirar capturas de ecrã"</string>
<string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignorar captura de ecrã"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação ignorada."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão ignorado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Painel de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Definições rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecrã de bloqueio."</string>
@@ -430,10 +431,9 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de ecrã"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslizar rapidamente para cima para mudar de aplicação"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de aplicação."</string>
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
+ <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslizar rapidamente para cima para mudar de app"</string>
+ <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de app."</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ativar/desativar Vista geral"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"A carregar"</string>
@@ -501,10 +501,10 @@
<string name="battery_saver_notification_title" msgid="8419266546034372562">"Poupança de bateria ativada"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduz o desempenho e os dados de segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Poupança de bateria"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"A aplicação <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"A app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que fornece esta função terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Pretende começar a gravar ou a transmitir?"</string>
- <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pretende começar a gravar ou a transmitir com a aplicação <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+ <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pretende começar a gravar ou a transmitir com a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar de novo"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string>
@@ -564,14 +564,14 @@
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Abrir credenciais fidedignas"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"O seu gestor ativou os registos de rede, que monitorizam o tráfego no seu dispositivo.\n\nPara obter mais informações, contacte o gestor."</string>
- <string name="monitoring_description_vpn" msgid="1685428000684586870">"Concedeu autorização a uma aplicação para configurar uma ligação VPN.\n\nEsta aplicação pode monitorizar a atividade do dispositivo e da rede, incluindo emails, aplicações e Sites."</string>
+ <string name="monitoring_description_vpn" msgid="1685428000684586870">"Concedeu autorização a uma app para configurar uma ligação VPN.\n\nEsta app pode monitorizar a atividade do dispositivo e da rede, incluindo emails, aplicações e Sites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu gestor tem a capacidade de monitorizar a sua atividade da rede, incluindo emails, aplicações e Sites.\n\nPara obter mais informações, contacte o gestor.\n\nAlém disso, está ligado a uma VPN, que pode monitorizar a sua atividade da rede."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
- <string name="monitoring_description_app" msgid="376868879287922929">"Está associado à aplicação <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a sua atividade de rede, incluindo emails, aplicações e Sites."</string>
+ <string name="monitoring_description_app" msgid="376868879287922929">"Está associado à app <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a sua atividade de rede, incluindo emails, aplicações e Sites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Sites."</string>
<string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Sites."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nContacte o gestor para obter mais informações."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à aplicação <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nTambém está associado à aplicação <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à app <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nContacte o gestor para obter mais informações."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à app <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nTambém está associado à app <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mantido desbloqueado pelo TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até ser desbloqueado manualmente"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -667,7 +667,7 @@
<string name="tuner_toast" msgid="3812684836514766951">"Parabéns! O Sintonizador da interface do sistema foi adicionado às Definições"</string>
<string name="remove_from_settings" msgid="633775561782209994">"Remover das Definições"</string>
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?"</string>
- <string name="activity_not_found" msgid="8711661533828200293">"A aplicação não está instalada no dispositivo"</string>
+ <string name="activity_not_found" msgid="8711661533828200293">"A app não está instalada no dispositivo"</string>
<string name="clock_seconds" msgid="8709189470828542071">"Mostrar segundos do relógio"</string>
<string name="clock_seconds_desc" msgid="2415312788902144817">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
<string name="qs_rearrange" msgid="484816665478662911">"Reorganizar as Definições rápidas"</string>
@@ -683,7 +683,7 @@
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"Controlos de notificações do consumo de energia"</string>
<string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Ativado"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Desativado"</string>
- <string name="power_notification_controls_description" msgid="1334963837572708952">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da aplicação"</string>
+ <string name="power_notification_controls_description" msgid="1334963837572708952">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da app"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"Notificações"</string>
<string name="notification_channel_disabled" msgid="928065923928416337">"Nunca mais verá estas notificações."</string>
<string name="notification_channel_minimized" msgid="6892672757877552959">"Estas notificações serão minimizadas."</string>
@@ -703,7 +703,7 @@
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Alertar"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Continuar a alertar"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desativar notificações"</string>
- <string name="inline_keep_showing_app" msgid="4393429060390649757">"Pretende continuar a ver notificações desta aplicação?"</string>
+ <string name="inline_keep_showing_app" msgid="4393429060390649757">"Pretende continuar a ver notificações desta app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string>
<string name="notification_alert_title" msgid="7629202599338071971">"Alertar"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Balão"</string>
@@ -714,26 +714,25 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Aparece na parte superior da secção de conversas e surge como um balão."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta definições específicas de conversas."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e ignorados vão aparecer aqui."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string>
- <string name="notification_delegate_header" msgid="1264510071031479920">"Notificação de aplicação proxy"</string>
- <string name="notification_channel_dialog_title" msgid="6856514143093200019">"Todas as notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_delegate_header" msgid="1264510071031479920">"Notificação de app proxy"</string>
+ <string name="notification_channel_dialog_title" msgid="6856514143093200019">"Todas as notificações da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="see_more_title" msgid="7409317011708185729">"Ver mais"</string>
- <string name="appops_camera" msgid="5215967620896725715">"Esta aplicação está a utilizar a câmara."</string>
- <string name="appops_microphone" msgid="8805468338613070149">"Esta aplicação está a utilizar o microfone."</string>
- <string name="appops_overlay" msgid="4822261562576558490">"Esta aplicação está a sobrepor-se a outras aplicações no ecrã."</string>
- <string name="appops_camera_mic" msgid="7032239823944420431">"Esta aplicação está a utilizar o microfone e a câmara."</string>
- <string name="appops_camera_overlay" msgid="6466845606058816484">"Esta aplicação está a sobrepor-se a outras aplicações no ecrã e a utilizar a câmara."</string>
- <string name="appops_mic_overlay" msgid="4609326508944233061">"Esta aplicação está a sobrepor-se a outras aplicações no ecrã e a utilizar o microfone."</string>
- <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"Esta aplicação está a sobrepor-se a outras aplicações no ecrã e a utilizar o microfone e a câmara."</string>
+ <string name="appops_camera" msgid="5215967620896725715">"Esta app está a utilizar a câmara."</string>
+ <string name="appops_microphone" msgid="8805468338613070149">"Esta app está a utilizar o microfone."</string>
+ <string name="appops_overlay" msgid="4822261562576558490">"Esta app está a sobrepor-se a outras aplicações no ecrã."</string>
+ <string name="appops_camera_mic" msgid="7032239823944420431">"Esta app está a utilizar o microfone e a câmara."</string>
+ <string name="appops_camera_overlay" msgid="6466845606058816484">"Esta app está a sobrepor-se a outras aplicações no ecrã e a utilizar a câmara."</string>
+ <string name="appops_mic_overlay" msgid="4609326508944233061">"Esta app está a sobrepor-se a outras aplicações no ecrã e a utilizar o microfone."</string>
+ <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"Esta app está a sobrepor-se a outras aplicações no ecrã e a utilizar o microfone e a câmara."</string>
<string name="notification_appops_settings" msgid="5208974858340445174">"Definições"</string>
<string name="notification_appops_ok" msgid="2177609375872784124">"OK"</string>
- <string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> abertos"</string>
- <string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> fechados"</string>
+ <string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"Controlos de notificações da app <xliff:g id="APP_NAME">%1$s</xliff:g> abertos"</string>
+ <string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"Controlos de notificações da app <xliff:g id="APP_NAME">%1$s</xliff:g> fechados"</string>
<string name="notification_channel_switch_accessibility" msgid="8979885820432540252">"Permitir notificações deste canal"</string>
<string name="notification_more_settings" msgid="4936228656989201793">"Mais definições"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"Personalizar"</string>
@@ -888,10 +887,10 @@
<string name="accessibility_qs_edit_tile_move" msgid="4841770637244326837">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g> para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
- <string name="dock_forced_resizable" msgid="4689301323912928801">"A aplicação pode não funcionar com o ecrã dividido."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7284915968096153808">"A aplicação não é compatível com o ecrã dividido."</string>
- <string name="forced_resizable_secondary_display" msgid="522558907654394940">"A aplicação pode não funcionar num ecrã secundário."</string>
- <string name="activity_launch_on_secondary_display_failed_text" msgid="8446727617187998208">"A aplicação não é compatível com o início em ecrãs secundários."</string>
+ <string name="dock_forced_resizable" msgid="4689301323912928801">"A app pode não funcionar com o ecrã dividido."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7284915968096153808">"A app não é compatível com o ecrã dividido."</string>
+ <string name="forced_resizable_secondary_display" msgid="522558907654394940">"A app pode não funcionar num ecrã secundário."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="8446727617187998208">"A app não é compatível com o início em ecrãs secundários."</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir as definições."</string>
<string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Abrir as definições rápidas."</string>
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fechar as definições rápidas."</string>
@@ -910,8 +909,8 @@
<string name="pip_phone_settings" msgid="5687538631925004341">"Definições"</string>
<string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrastar para baixo para ignorar"</string>
<string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"A aplicação <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se não pretende que a aplicação <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
+ <string name="pip_notification_title" msgid="8661573026059630525">"A app <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
+ <string name="pip_notification_message" msgid="4991831338795022227">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
<string name="pip_play" msgid="333995977693142810">"Reproduzir"</string>
<string name="pip_pause" msgid="1139598607050555845">"Colocar em pausa"</string>
<string name="pip_skip_to_next" msgid="3864212650579956062">"Mudar para o seguinte"</string>
@@ -930,7 +929,7 @@
<string name="lockscreen_unlock_left" msgid="1417801334370269374">"O atalho esquerdo também desbloqueia"</string>
<string name="lockscreen_unlock_right" msgid="4658008735541075346">"O atalho direito também desbloqueia"</string>
<string name="lockscreen_none" msgid="4710862479308909198">"Nenhum"</string>
- <string name="tuner_launch_app" msgid="3906265365971743305">"Iniciar a aplicação <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_launch_app" msgid="3906265365971743305">"Iniciar a app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="tuner_other_apps" msgid="7767462881742291204">"Outras aplicações"</string>
<string name="tuner_circle" msgid="5270591778160525693">"Círculo"</string>
<string name="tuner_plus" msgid="4130366441154416484">"Mais"</string>
@@ -947,9 +946,9 @@
<string name="notification_channel_hints" msgid="7703783206000346876">"Sugestões"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplicações instantâneas"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
- <string name="instant_apps_message" msgid="6112428971833011754">"A aplicação é aberta sem ser instalada."</string>
- <string name="instant_apps_message_with_help" msgid="1816952263531203932">"A aplicação é aberta sem ser instalada. Toque para saber mais."</string>
- <string name="app_info" msgid="5153758994129963243">"Info. da aplicação"</string>
+ <string name="instant_apps_message" msgid="6112428971833011754">"A app é aberta sem ser instalada."</string>
+ <string name="instant_apps_message_with_help" msgid="1816952263531203932">"A app é aberta sem ser instalada. Toque para saber mais."</string>
+ <string name="app_info" msgid="5153758994129963243">"Info. da app"</string>
<string name="go_to_web" msgid="636673528981366511">"Ir para o navegador"</string>
<string name="mobile_data" msgid="4564407557775397216">"Dados móveis"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
@@ -958,8 +957,8 @@
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desativado"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Não incomodar desativado"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"O modo Não incomodar foi ativado por uma regra automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"O modo Não incomodar foi ativado por uma aplicação (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"O modo Não incomodar foi ativado por uma regra automática ou por uma aplicação."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"O modo Não incomodar foi ativado por uma app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"O modo Não incomodar foi ativado por uma regra automática ou por uma app."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"Até à(s) <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="qs_dnd_keep" msgid="3829697305432866434">"Manter"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"Substituir"</string>
@@ -968,11 +967,11 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Pretende desativar os dados móveis?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o seu operador"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"Uma vez que uma aplicação está a ocultar um pedido de autorização, as Definições não conseguem validar a sua resposta."</string>
- <string name="slice_permission_title" msgid="3262615140094151017">"Permitir que a aplicação <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
- <string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações da aplicação <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="slice_permission_text_2" msgid="6758906940360746983">"- Pode realizar ações na aplicação <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="slice_permission_checkbox" msgid="4242888137592298523">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer aplicação"</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"Uma vez que uma app está a ocultar um pedido de autorização, as Definições não conseguem validar a sua resposta."</string>
+ <string name="slice_permission_title" msgid="3262615140094151017">"Permitir que a app <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+ <string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações da app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="slice_permission_text_2" msgid="6758906940360746983">"- Pode realizar ações na app <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="slice_permission_checkbox" msgid="4242888137592298523">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"Permitir"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"Recusar"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"Tocar para agendar a Poupança de bateria"</string>
@@ -986,8 +985,8 @@
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
- <string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar esta aplicação e ficar em ecrã inteiro."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Definições dos balões da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar esta app e ficar em ecrã inteiro."</string>
+ <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Definições dos balões da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="manage_bubbles_text" msgid="6856830436329494850">"Gerir"</string>
<string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do <xliff:g id="APP_NAME">%2$s</xliff:g> e mais<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controlos a que pretende aceder a partir do menu ligar/desligar."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Toque sem soltar e arraste para reorganizar os controlos."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controlos foram removidos."</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Alterações não guardadas."</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista dos controlos."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicione aos controlos de dispositivos"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6e97aa6..c22a277 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação dispensada."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão dispensado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantenha a tela pressionada e arraste para reorganizar os controles"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index fed4441..519eddda 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificarea a fost închisă."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balonul a fost respins."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Fereastră pentru notificări."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setări rapide."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecranul de blocare."</string>
@@ -1032,8 +1033,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Alegeți comenzile de accesat din meniul de alimentare"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Țineți apăsat și trageți pentru a rearanja comenzile"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Au fost șterse toate comenzile"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modificările nu au fost salvate"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista cu toate comenzile nu a putut fi încărcată."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Adăugați la comenzile dispozitivelor"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f7638ce..ad7f175 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Уведомление закрыто"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Всплывающий чат закрыт."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель уведомлений"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Быстрые настройки"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блокировки."</string>
@@ -1038,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Выберите элементы управления, которые будут доступны в меню кнопки питания."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Чтобы изменить порядок элементов управления, перетащите их"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Все элементы управления удалены"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Изменения не сохранены."</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не удалось загрузить список элементов управления."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Добавьте виджеты управления устройствами"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2bcd5e3..2011bf0 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"දැනුම්දීම නිෂ්ප්රභා කරඇත."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"බුබුල ඉවත දමා ඇත."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"දැනුම්දීම් ආවරණය."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ක්ෂණික සැකසීම්."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"අගුළු තිරය."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"බල මෙනුවෙන් ප්රවේශ වීමට පාලන තෝරා ගන්න"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"පාලන නැවත පිළියෙළ කිරීමට අල්ලාගෙන සිට අදින්න"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"සියලු පාලන ඉවත් කර ඇත"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"වෙනස් කිරීම් නොසුරැකිණි"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"සියලු පාලනවල ලැයිස්තුව පූරණය කළ නොහැකි විය."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"උපාංග පාලන වෙත එක් කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 620bcd6..6fd6d87 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -163,7 +163,7 @@
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Ak pri ďalšom pokuse zadáte nesprávny kód PIN, tento používateľ bude odstránený."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Ak pri ďalšom pokuse zadáte nesprávne heslo, tento používateľ bude odstránený."</string>
<string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ak pri ďalšom pokuse zadáte nesprávny vzor, váš pracovný profil a jeho dáta budú odstránené."</string>
- <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ak pri ďalšom pokuse zadáte nesprávny kód PIN, váš pracovný profil a jeho dáta budú odstránené."</string>
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ak pri ďalšom pokuse zadáte nesprávny PIN, váš pracovný profil a jeho dáta budú odstránené."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ak pri ďalšom pokuse zadáte nesprávne heslo, váš pracovný profil a jeho dáta budú odstránené."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Príliš veľa chybných pokusov. Dáta tohto zariadenia budú odstránené."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Príliš veľa chybných pokusov. Tento používateľ bude odstránený."</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Upozornenie bolo zrušené."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bublina bola zavretá."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel upozornení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rýchle nastavenia."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Uzamknutá obrazovka"</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Záznam obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začať"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončiť"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Zariadenie"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Potiahnutím nahor prepnete aplikácie"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Presunutím doprava rýchlo prepnete aplikácie"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Prepnúť prehľad"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Zobrazuje sa v hornej časti konverzácie ako bublina."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavenia konkrétnych konverzácií"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žiadne nedávne bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte si ovládacie prvky, ku ktorým chcete mať prístup v ponuke vypínača"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Ovládacie prvky môžete usporiadať pridržaním a presunutím"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Všetky ovládacie prvky boli odstránené"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmeny neboli uložené"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Pridanie do ovládania zariadenia"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ba73b1a..aade5c2 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obvestilo je bilo odstranjeno."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblaček je bil opuščen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon z obvestili."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hitre nastavitve."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaklenjen zaslon"</string>
@@ -438,7 +439,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Za preklop aplikacij povlecite navzgor"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Povlecite v desno za hiter preklop med aplikacijami"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Vklop/izklop pregleda"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Akumulator napolnjen"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Baterija napolnjena"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Polnjenje"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Se ne polni"</string>
@@ -1038,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izberite kontrolnike, do katerih želite imeti dostop prek menija za vklop/izklop"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Držite in povlecite, da prerazporedite kontrolnike"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Vsi kontrolniki so bili odstranjeni"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Spremembe niso shranjene"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Seznama vseh kontrolnikov ni bilo mogoče naložiti."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Dodajanje med kontrolnike naprave"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 392c1f1..0d85f21 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Njoftimi është hequr."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Flluska u hoq."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Streha e njoftimeve."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cilësimet e shpejta."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekrani i kyçjes."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Regjistrimi i ekranit"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Nis"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ndalo"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Pajisja"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rrëshqit shpejt lart për të ndërruar aplikacionet"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zvarrit djathtas për të ndërruar aplikacionet me shpejtësi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kalo te përmbledhja"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Shfaqet në krye të seksionit të bisedës dhe shfaqet si flluskë."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk i mbështet cilësimet specifike të bisedës"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nuk ka flluska të fundit"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Zgjidh kontrollet për të pasur qasje nga menyja e energjisë"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mbaje të shtypur dhe zvarrit për të risistemuar kontrollet"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Të gjitha kontrollet u hoqën"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ndryshimet nuk u ruajtën"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista e të gjitha kontrolleve nuk mund të ngarkohej."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Shto te kontrollet e pajisjes"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 54d7fc8..7fd0371 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -63,7 +63,7 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дозволи"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Отклањање грешака на USB-у није дозвољено"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Корисник који је тренутно пријављен на овај уређај не може да укључи отклањање грешака на USB-у. Да бисте користили ову функцију, пребаците на примарног корисника."</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Желите ли да омогућите бежично отклањање грешака на овој мрежи?"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Желите да омогућите бежично отклањање грешака на овој мрежи?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Назив мреже (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi адреса (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Увек дозволи на овој мрежи"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Дозволи"</string>
@@ -162,12 +162,12 @@
<string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо овог корисника."</string>
<string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо овог корисника."</string>
<string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо овог корисника."</string>
- <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо профил за Work и његове податке."</string>
- <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо профил за Work и његове податке."</string>
- <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо профил за Work и његове податке."</string>
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
+ <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Превише нетачних покушаја. Избрисаћемо податке са овог уређаја."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Превише нетачних покушаја. Избрисаћемо овог корисника."</string>
- <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Превише нетачних покушаја. Избрисаћемо овај профил за Work и његове податке."</string>
+ <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Превише нетачних покушаја. Избрисаћемо овај пословни профил и његове податке."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Одбаци"</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Додирните сензор за отисак прста"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона отиска прста"</string>
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Обавештење је одбачено."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Облачић је одбачен."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Прозор са обавештењима."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брза подешавања."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Закључан екран."</string>
@@ -414,7 +415,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Искористили сте <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ограничење од <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Профил за Work"</string>
+ <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Пословни профил"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ноћно светло"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Укључује се по заласку сунца"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"До изласка сунца"</string>
@@ -529,11 +530,11 @@
<string name="quick_settings_disclosure_named_management" msgid="586473803771171610">"Овим уређајем управља <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_management_vpns" msgid="3447553497516286109">"Уређајем управља организација и повезан је са VPN-овима"</string>
<string name="quick_settings_disclosure_named_management_vpns" msgid="4066586579688193212">"Уређајем управља <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> и повезан је са VPN-овима"</string>
- <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Организација може да прати мрежни саобраћај на профилу за Work"</string>
- <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> може да надгледа мрежни саобраћај на профилу за Work"</string>
+ <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Организација може да прати мрежни саобраћај на пословном профилу"</string>
+ <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> може да надгледа мрежни саобраћај на пословном профилу"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Мрежа се можда надгледа"</string>
<string name="quick_settings_disclosure_vpns" msgid="2890510056934492407">"Уређај је повезан са VPN-овима"</string>
- <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="5149334449426566152">"Профил за Work је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="5149334449426566152">"Пословни профил је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="4201831495800021670">"Лични профил је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_named_vpn" msgid="5069088739435424666">"Уређај је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="monitoring_title_device_owned" msgid="7029691083837606324">"Управљање уређајима"</string>
@@ -548,12 +549,12 @@
<string name="monitoring_description_named_management" msgid="7424612629468754552">"Уређајем управља <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nАдминистратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nВише информација потражите од администратора."</string>
<string name="monitoring_description_management" msgid="8081910434889677718">"Уређајем управља организација.\n\nАдминистратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nВише информација потражите од администратора."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Организација је на овом уређају инсталирала ауторитет за издавање сертификата. Безбедни мрежни саобраћај може да се прати или мења."</string>
- <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Организација је на профилу за Work инсталирала ауторитет за издавање сертификата. Безбедни мрежни саобраћај може да се прати или мења."</string>
+ <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Организација је на пословном профилу инсталирала ауторитет за издавање сертификата. Безбедни мрежни саобраћај може да се прати или мења."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"На овом уређају је инсталиран ауторитет за издавање сертификата. Безбедни мрежни саобраћај може да се прати или мења."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Администратор је укључио евидентирање мреже, које прати саобраћај на уређају."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Повезани сте са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Повезани сте са апликацијама <xliff:g id="VPN_APP_0">%1$s</xliff:g> и <xliff:g id="VPN_APP_1">%2$s</xliff:g>, које могу да надгледају активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Профил за Work је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Пословни профил је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Лични профил је повезан са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Уређајем управља <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> користи <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> за управљање уређајем."</string>
@@ -567,13 +568,13 @@
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Отворите поуздане акредитиве"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Администратор је укључио евидентирање мреже, које прати саобраћај на уређају.\n\nКонтактирајте администратора за више информација."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Дали сте дозволу апликацији да подешава VPN везу.\n\nТа апликација може да надгледа активности на уређају и мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управља профилом за Work.\n\nАдминистратор може да прати активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nКонтактирајте администратора за више информација.\n\nПовезани сте и са VPN-ом, који може да прати активности на мрежи."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управља пословним профилом.\n\nАдминистратор може да прати активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nКонтактирајте администратора за више информација.\n\nПовезани сте и са VPN-ом, који може да прати активности на мрежи."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
<string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"Пословним профилом управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Пословним профилом управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Поуздани агент спречава закључавање"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Уређај ће остати закључан док га не откључате ручно"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -651,7 +652,7 @@
<string name="show_demo_mode" msgid="3677956462273059726">"Прикажи режим демонстрације"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"Етернет"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Аларм"</string>
- <string name="status_bar_work" msgid="5238641949837091056">"Профил за Work"</string>
+ <string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string>
<string name="add_tile" msgid="6239678623873086686">"Додај плочицу"</string>
<string name="broadcast_tile" msgid="5224010633596487481">"Плочица за емитовање"</string>
@@ -661,7 +662,7 @@
<string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Брза подешавања, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Хотспот"</string>
- <string name="accessibility_managed_profile" msgid="4703836746209377356">"Профил за Work"</string>
+ <string name="accessibility_managed_profile" msgid="4703836746209377356">"Пословни профил"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за неке, али не за све"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Тјунер за кориснички интерфејс система вам пружа додатне начине за подешавање и прилагођавање Android корисничког интерфејса. Ове експерименталне функције могу да се промене, откажу или нестану у будућим издањима. Будите опрезни."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Ове експерименталне функције могу да се промене, откажу или нестану у будућим издањима. Будите опрезни."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 70e97f2..f915f6c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Meddelandet ignorerades."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubblan ignorerades."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meddelandepanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snabbinställningar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låsskärm."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skärminspelning"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starta"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppa"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Byt appar genom att svepa uppåt"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tryck och dra åt höger för att snabbt byta mellan appar"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktivera och inaktivera översikten"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Visas högst upp bland konversationerna som en bubbla"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsspecifika inställningar"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga nya bubblor"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"De senaste bubblorna och ignorerade bubblor visas här"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Välj snabbkontroller som ska visas i strömbrytarmenyn"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Ändra ordning på kontrollerna genom att trycka och dra"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alla kontroller har tagits bort"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ändringarna har inte sparats"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listan med alla kontroller kunde inte läsas in."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Lägg till i enhetsstyrning"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 6ea4253..20e0325 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Arifa imetupwa."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Umeondoa kiputo."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kivuli cha arifa."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mipangilio ya haraka."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Skrini iliyofungwa."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rekodi ya Skrini"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Anza kurekodi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Acha kurekodi"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Kifaa"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Telezesha kidole juu ili ubadilishe programu"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Buruta kulia ili ubadilishe programu haraka"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Washa Muhtasari"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Huonyeshwa sehemu ya juu ya mazungumzo na huonekana kama kiputo."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii mipangilio mahususi ya mazungumzo"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hakuna viputo vya hivi majuzi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Chagua vidhibiti vya kufikia ukitumia menyu ya kuwasha/kuzima"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Shikilia na uburute ili upange upya vidhibiti"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Umeondoa vidhibiti vyote"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Mabadiliko hayajahifadhiwa"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Weka kwenye vidhibiti vya vifaa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 81204e3..e38fbaa 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"அறிவிப்பு விவரம்."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"உடனடி அமைப்பு."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"லாக் ஸ்கிரீன்."</string>
@@ -1003,8 +1005,7 @@
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"குமிழ்களை எப்போது வேண்டுமானாலும் கட்டுப்படுத்தலாம்"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"இந்த ஆப்ஸிலிருந்து வரும் குமிழ்களை முடக்க, நிர்வகி என்பதைத் தட்டவும்"</string>
<string name="bubbles_user_education_got_it" msgid="8282812431953161143">"சரி"</string>
- <!-- no translation found for bubbles_app_settings (5779443644062348657) -->
- <skip />
+ <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> அமைப்புகள்"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"சிஸ்டம் நேவிகேஷன் மாற்றப்பட்டது. மாற்றங்களைச் செய்ய ‘அமைப்புகளுக்குச்’ செல்லவும்."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index cfd420a..ddeab71 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -255,6 +255,8 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"నోటిఫికేషన్ తీసివేయబడింది."</string>
+ <!-- no translation found for accessibility_bubble_dismissed (270358867566720729) -->
+ <skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్లు."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string>
@@ -430,8 +432,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"స్క్రీన్ రికార్డ్"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించు"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"పరికరం"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"యాప్లను మార్చడం కోసం ఎగువకు స్వైప్ చేయండి"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"యాప్లను శీఘ్రంగా స్విచ్ చేయడానికి కుడి వైపుకు లాగండి"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
@@ -714,8 +715,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"సంభాషణ విభాగానికి ఎగువున ఉంటుంది, బబుల్లాగా కనిపిస్తుంది."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్లు"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"\'సంభాషణ నిర్దిష్ట సెట్టింగ్\'లకు <xliff:g id="APP_NAME">%1$s</xliff:g> సపోర్ట్ చేయదు"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్, తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్లను సవరించడం వీలుపడదు."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 45a0661..332155f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ปิดการแจ้งเตือนแล้ว"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ปิดบับเบิลแล้ว"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"หน้าต่างแจ้งเตือน"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"การตั้งค่าด่วน"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ล็อกหน้าจอ"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"เลือกตัวควบคุมที่ต้องการให้เข้าถึงได้จากเมนูเปิด/ปิด"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"กดตัวควบคุมค้างไว้แล้วลากเพื่อจัดเรียงใหม่"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"นำตัวควบคุมทั้งหมดออกแล้ว"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ยังไม่ได้บันทึกการเปลี่ยนแปลง"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"เพิ่มไปยังระบบควบคุมอุปกรณ์"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index db00e8a..d344a1e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Na-dismiss ang notification."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Na-dismiss na ang bubble."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mga mabilisang setting."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pumili ng mga kontrol na maa-access mula sa power menu"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"I-hold at i-drag para baguhin ang pagkakaayos ng mga kontrol"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Inalis ang lahat ng kontrol"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Hindi na-save ang mga pagbabago"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Hindi ma-load ang listahan ng lahat ng control."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Idagdag sa mga kontrol ng device"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 51aad9d..7e9280d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Bildirim kapatıldı."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balon kapatıldı."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildirim gölgesi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hızlı ayarlar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilit ekranı"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran Kaydı"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlat"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Durdur"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Uygulamalar arasında geçiş yapmak için yukarı kaydırın"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Uygulamaları hızlıca değiştirmek için sağa kaydırın"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Genel bakışı aç/kapat"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Görüşme bölümünün üstünde baloncuk olarak gösterilir."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>, görüşmeye özgü ayarları desteklemiyor"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Son kapatılan baloncuk yok"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Güç menüsünden erişmek için denetimleri seçin"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Kontrolleri yeniden düzenlemek için basılı tutup sürükleyin"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Tüm kontroller kaldırıldı"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Değişiklikler kaydedilmedi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Tüm kontrollerin listesi yüklenemedi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz denetimlerine ekle"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index fe63ad6..5bb59eb 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Сповіщення відхилено."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Спливаюче сповіщення закрито."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель сповіщень."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Швидке налаштування."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заблокований екран."</string>
@@ -434,8 +435,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запис екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почати"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зупинити"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Пристрій"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Проводьте пальцем угору, щоб переходити між додатками"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Перетягуйте праворуч, щоб швидко переходити між додатками"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Увімкнути або вимкнути огляд"</string>
@@ -720,8 +720,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"З\'являється вгорі розділу з розмовами у вигляді спливаючого чату."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує налаштування для чату"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих чатів"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
@@ -1040,8 +1039,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Виберіть, які елементи керування будуть у меню \"Живлення\""</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Щоб змінити порядок елементів керування, перетягуйте їх"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Усі елементи керування вилучено"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Зміни не збережено"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не вдалося завантажити список усіх елементів керування."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Додати до елементів керування пристроями"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index eb5094d..6129f2a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"اطلاع مسترد ہوگئی۔"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"بلبلہ مسترد کر دیا گیا۔"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"اسکرین ریکارڈر کریں"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"آغاز"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"روکیں"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"آلہ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ایپس سوئچ کرنے کیلئے اوپر سوائپ کریں"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"تیزی سے ایپس کو سوئچ کرنے کے لیے دائیں طرف گھسیٹیں"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"مجموعی جائزہ ٹوگل کریں"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"گفتگو کے سیکشن میں سب سے اوپر دکھاتا ہے اور بلبلہ کے طور پر ظاہر ہوتا ہے۔"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو سے متعلق مخصوص ترتیبات کو سپورٹ نہیں کرتی"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"کوئی حالیہ بلبلہ نہیں"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"پاور مینو سے رسائی حاصل کرنے کے لیے کنٹرولز کو منتخب کریں"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"کنٹرولز کو دوبارہ ترتیب دینے کے ليے پکڑیں اور گھسیٹیں"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"سبھی کنٹرولز ہٹا دیے گئے"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"تبدیلیاں محفوظ نہیں ہوئیں"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تمام کنٹرولز کی فہرست لوڈ نہیں کی جا سکی۔"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"آلہ کے کنٹرولز میں شامل کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index c83f977..e9b0083 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Xabarnoma e‘tiborsiz qoldirildi."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulutchali xabar yopildi."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Xabarnoma soyasi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tezkor sozlamalar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Qulflash ekrani."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Quvvat tugmasi menyusida chiqadigan boshqaruv elementlarini tanlang"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Boshqaruv elementlarini qayta tartiblash uchun ushlab torting"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Barcha boshqaruv elementlari olib tashlandi"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Oʻzgartirishlar saqlanmadi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Boshqaruv elementlarining barchasi yuklanmadi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Qurilma boshqaruv elementlariga kiritish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 63af035..3b5e8b1 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Đã loại bỏ thông báo."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Đã đóng bong bóng."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bóng thông báo."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cài đặt nhanh."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Màn hình khóa."</string>
@@ -430,8 +431,7 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ghi lại nội dung trên màn hình"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Bắt đầu"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dừng"</string>
- <!-- no translation found for media_seamless_remote_device (177033467332920464) -->
- <skip />
+ <string name="media_seamless_remote_device" msgid="177033467332920464">"Thiết bị"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vuốt lên để chuyển đổi ứng dụng"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Kéo sang phải để chuyển đổi nhanh giữa các ứng dụng"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Bật/tắt chế độ xem Tổng quan"</string>
@@ -714,8 +714,7 @@
<string name="notification_channel_summary_priority" msgid="7415770044553264622">"Hiển thị dưới dạng bong bóng ở đầu cuộc trò chuyện."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
- <!-- no translation found for no_shortcut (7176375126961212514) -->
- <skip />
+ <string name="no_shortcut" msgid="7176375126961212514">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ tùy chọn cài đặt dành riêng cho cuộc trò chuyện"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Không có bong bóng trò chuyện nào gần đây"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
@@ -1028,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Chọn các tùy chọn điều khiển để truy cập từ trình đơn nguồn"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Giữ và kéo để sắp xếp lại các tùy chọn điều khiển"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Đã xóa tất cả tùy chọn điều khiển"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Chưa lưu các thay đổi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Không thể tải danh sách tất cả tùy chọn điều khiển."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Thêm vào mục điều khiển thiết bị"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 323324d..f547280 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"已关闭通知。"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"已关闭对话泡。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知栏。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷设置。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"锁定屏幕。"</string>
@@ -413,7 +414,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"上限为<xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
<string name="quick_settings_work_mode_label" msgid="2754212289804324685">"工作资料"</string>
- <string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜间模式"</string>
+ <string name="quick_settings_night_display_label" msgid="8180030659141778180">"护眼模式"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"在日落时开启"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"在日出时关闭"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"在<xliff:g id="TIME">%s</xliff:g> 开启"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"选择要从电源菜单访问的控件"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"按住并拖动即可重新排列控件"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控件"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未保存更改"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控制器"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f78604c..5f5b4cb 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"通知已關閉。"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"對話氣泡已關閉。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快速設定。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"上鎖畫面。"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"從電源選單選擇要存取的控制項"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"按住並拖曳便可重新排列控制項"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控制項"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未儲存變更"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"加到裝置控制"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 141452b..ba30f14 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"已關閉通知。"</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"已關閉泡泡。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷設定。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"螢幕鎖定。"</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"選擇要從電源選單存取的控制項"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"按住並拖曳即可重新排列控制項"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"所有控制項都已移除"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未儲存變更"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整的控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b6de81b..2f8dad9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -255,6 +255,7 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Isaziso sichithiwe."</string>
+ <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ibhamuza licashisiwe."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Umthunzi wesaziso."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Izilingiselelo ezisheshayo."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Khiya isikrini."</string>
@@ -1026,8 +1027,7 @@
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Khetha izilawuli ukuze ufinyelele kusuka kumenyu yamandla"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Bamba futhi uhudule ukuze uphinde ulungise izilawuli"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Zonke izilawuli zisusiwe"</string>
- <!-- no translation found for controls_favorite_toast_no_changes (7094494210840877931) -->
- <skip />
+ <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Izinguquko azilondolozwanga"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Uhlu lwazo zonke izilawuli alilayishekanga."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string>
<string name="controls_dialog_title" msgid="2343565267424406202">"Engeza kuzilawuli zezinsiza"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d3256ef..c419594 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -154,5 +154,12 @@
<declare-styleable name="CaptionsToggleImageButton">
<attr name="optedOut" format="boolean" />
</declare-styleable>
+
+ <declare-styleable name="IlluminationDrawable">
+ <attr name="highlight" format="integer" />
+ <attr name="cornerRadius" format="dimension" />
+ <attr name="rippleMinSize" format="dimension" />
+ <attr name="rippleMaxSize" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 82eda31..b677600 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -200,6 +200,7 @@
<color name="global_screenshot_button_icon">@color/GM2_blue_500</color>
<color name="global_screenshot_dismiss_background">#FFFFFF</color>
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
+ <color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 62335ab..1407574 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -128,6 +128,13 @@
night,dark,dnd,flashlight,rotation,location
</string>
+ <!-- Tiles to auto add to Quick Settings upon first change of a given secure setting.
+ The syntax is setting-name:spec. If the tile is a TileService, the spec should be specified
+ as custom(package/class). Relative class name is supported. -->
+ <string-array name="config_quickSettingsAutoAdd" translatable="false">
+ <item>accessibility_display_inversion_enabled:inversion</item>
+ </string-array>
+
<!-- Whether or not the RSSI tile is capitalized or not. -->
<bool name="quick_settings_rssi_tile_capitalization">true</bool>
@@ -523,6 +530,10 @@
<!-- ID for the camera that needs extra protection -->
<string translatable="false" name="config_protectedCameraId"></string>
+ <!-- Comma-separated list of packages to exclude from camera protection e.g.
+ "com.android.systemui,com.android.xyz" -->
+ <string translatable="false" name="config_cameraProtectionExcludedPackages"></string>
+
<!-- Flag to turn on the rendering of the above path or not -->
<bool name="config_enableDisplayCutoutProtection">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 48648e5..99e347e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -304,7 +304,9 @@
<!-- The padding on the global screenshot background image -->
<dimen name="global_screenshot_legacy_bg_padding">20dp</dimen>
<dimen name="global_screenshot_bg_padding">20dp</dimen>
+ <dimen name="global_screenshot_bg_protection_height">400dp</dimen>
<dimen name="global_screenshot_x_scale">80dp</dimen>
+ <dimen name="screenshot_bg_protection_height">242dp</dimen>
<dimen name="screenshot_preview_elevation">6dp</dimen>
<dimen name="screenshot_offset_y">48dp</dimen>
<dimen name="screenshot_offset_x">16dp</dimen>
@@ -994,7 +996,7 @@
<dimen name="pip_expand_container_edge_margin">30dp</dimen>
<!-- The touchable/draggable edge size for PIP resize. -->
- <dimen name="pip_resize_edge_size">30dp</dimen>
+ <dimen name="pip_resize_edge_size">48dp</dimen>
<!-- The corner radius for PiP window. -->
<dimen name="pip_corner_radius">8dp</dimen>
@@ -1167,7 +1169,7 @@
<!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
<!-- Default height of bubble overflow -->
- <dimen name="bubble_overflow_height">460dp</dimen>
+ <dimen name="bubble_overflow_height">480dp</dimen>
<!-- Bubble overflow padding when there are no bubbles -->
<dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
<!-- Padding of container for overflow bubbles -->
@@ -1249,9 +1251,17 @@
<!-- Home Controls -->
<dimen name="controls_header_side_margin">4dp</dimen>
<dimen name="controls_header_menu_size">48dp</dimen>
- <dimen name="controls_header_app_icon_size">40dp</dimen>
- <dimen name="controls_top_margin">44dp</dimen>
- <dimen name="control_header_text_size">22sp</dimen>
+ <dimen name="controls_header_bottom_margin">24dp</dimen>
+ <dimen name="controls_header_app_icon_size">24dp</dimen>
+ <dimen name="controls_top_margin">48dp</dimen>
+ <dimen name="control_header_text_size">20sp</dimen>
+ <dimen name="control_item_text_size">16sp</dimen>
+ <dimen name="control_menu_item_text_size">16sp</dimen>
+ <dimen name="control_menu_item_min_height">56dp</dimen>
+ <dimen name="control_menu_vertical_padding">12dp</dimen>
+ <dimen name="control_menu_horizontal_padding">16dp</dimen>
+ <dimen name="control_spinner_padding_vertical">24dp</dimen>
+ <dimen name="control_spinner_padding_horizontal">20dp</dimen>
<dimen name="control_text_size">14sp</dimen>
<dimen name="control_icon_size">24dp</dimen>
<dimen name="control_spacing">4dp</dimen>
@@ -1268,20 +1278,29 @@
<fraction name="controls_dimmed_alpha">40%</fraction>
<!-- Home Controls activity view detail panel-->
- <dimen name="controls_activity_view_top_padding">25dp</dimen>
- <dimen name="controls_activity_view_side_padding">12dp</dimen>
<dimen name="controls_activity_view_top_offset">100dp</dimen>
<dimen name="controls_activity_view_text_size">17sp</dimen>
+ <dimen name="controls_activity_view_corner_radius">@*android:dimen/config_bottomDialogCornerRadius</dimen>
<!-- Home Controls management screens -->
<dimen name="controls_management_top_padding">48dp</dimen>
- <dimen name="controls_management_side_padding">8dp</dimen>
- <dimen name="controls_management_titles_margin">8dp</dimen>
+ <dimen name="controls_management_side_padding">16dp</dimen>
+ <dimen name="controls_management_titles_margin">16dp</dimen>
+ <dimen name="controls_management_footer_side_margin">8dp</dimen>
<dimen name="controls_management_list_margin">16dp</dimen>
- <dimen name="controls_title_size">26sp</dimen>
+ <dimen name="controls_management_apps_list_margin">64dp</dimen>
+ <dimen name="controls_management_editing_list_margin">48dp</dimen>
+ <dimen name="controls_management_editing_divider_margin">24dp</dimen>
+ <dimen name="controls_management_apps_extra_side_margin">8dp</dimen>
+ <dimen name="controls_management_apps_top_margin"></dimen>
+ <dimen name="controls_management_zone_top_margin">32dp</dimen>
+ <dimen name="controls_management_page_indicator_height">24dp</dimen>
+ <dimen name="controls_management_checkbox_size">25dp</dimen>
+ <dimen name="controls_title_size">24sp</dimen>
+ <dimen name="controls_subtitle_size">16sp</dimen>
- <dimen name="controls_app_icon_size">32dp</dimen>
- <dimen name="controls_app_icon_frame_side_padding">8dp</dimen>
+ <dimen name="controls_app_icon_size">24dp</dimen>
+ <dimen name="controls_app_icon_frame_side_padding">16dp</dimen>
<dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
<dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen>
<dimen name="controls_app_bottom_margin">8dp</dimen>
@@ -1292,7 +1311,7 @@
<dimen name="controls_card_margin">2dp</dimen>
<item name="control_card_elevation" type="dimen" format="float">15</item>
- <dimen name="controls_dialog_padding">8dp</dimen>
+ <dimen name="controls_dialog_padding">32dp</dimen>
<dimen name="controls_dialog_control_width">200dp</dimen>
<!-- Screen Record -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 04640f4..8156e8dc 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -144,5 +144,10 @@
<!-- NotificationPanelView -->
<item type="id" name="notification_panel" />
+
+ <!-- Screen Recording -->
+ <item type="id" name="screen_recording_options" />
+ <item type="id" name="screen_recording_dialog_source_text" />
+ <item type="id" name="screen_recording_dialog_source_description" />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fd9a8d1d..ec29622 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_name">Screen Recorder</string>
+ <!-- Processing screen recoding video in the background [CHAR LIMIT=30]-->
+ <string name="screenrecord_background_processing_label">Processing screen recording</string>
<!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]-->
<string name="screenrecord_channel_description">Ongoing notification for a screen record session</string>
<!-- Title for the screen prompting the user to begin recording their screen [CHAR LIMIT=NONE]-->
@@ -1253,6 +1255,9 @@
<!-- The text for the notification history link. [CHAR LIMIT=40] -->
<string name="manage_notifications_history_text">History</string>
+ <!-- Section title for notifications that have recently appeared. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_incoming">Incoming</string>
+
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
@@ -2608,6 +2613,10 @@
<!-- Text used for content description of settings button in the header of expanded bubble
view. [CHAR_LIMIT=NONE] -->
<string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
+ <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
+ <string name="bubble_overflow_button_content_description">Overflow</string>
+ <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
+ <string name="bubble_accessibility_action_add_back">Add back to stack</string>
<!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
<string name="manage_bubbles_text">Manage</string>
<!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
@@ -2651,13 +2660,13 @@
<string name="inattentive_sleep_warning_title">Standby</string>
<!-- Priority conversation onboarding screen -->
- <!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=50] -->
+ <!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=75] -->
<string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string>
- <!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=50] -->
+ <!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=75] -->
<string name="priority_onboarding_show_avatar_text">Show profile picture on lock screen</string>
- <!-- Text explaining that priority conversations will appear as a bubble [CHAR LIMIT=50] -->
+ <!-- Text explaining that priority conversations will appear as a bubble [CHAR LIMIT=75] -->
<string name="priority_onboarding_appear_as_bubble_text">Appear as a floating bubble on top of apps</string>
- <!-- Text explaining that priority conversations can interrupt DnD settings [CHAR LIMIT=50] -->
+ <!-- Text explaining that priority conversations can interrupt DnD settings [CHAR LIMIT=75] -->
<string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string>
<!-- Title for the affirmative button [CHAR LIMIT=50] -->
<string name="priority_onboarding_done_button_title">Got it</string>
@@ -2710,9 +2719,9 @@
<!-- Controls dialog title [CHAR LIMIT=40] -->
<string name="controls_dialog_title">Add to device controls</string>
<!-- Controls dialog add to favorites [CHAR LIMIT=40] -->
- <string name="controls_dialog_ok">Add to favorites</string>
- <!-- Controls dialog message [CHAR LIMIT=NONE] -->
- <string name="controls_dialog_message"><xliff:g id="app" example="System UI">%s</xliff:g> suggested this control to add to your favorites.</string>
+ <string name="controls_dialog_ok">Add</string>
+ <!-- Controls dialog message. Indicates app that suggested this control [CHAR LIMIT=NONE] -->
+ <string name="controls_dialog_message">Suggested by <xliff:g id="app" example="System UI">%s</xliff:g></string>
<!-- Controls dialog confirmation [CHAR LIMIT=30] -->
<string name="controls_dialog_confirmation">Controls updated</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 57d2040..f0edd63 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -620,6 +620,10 @@
<item name="rotateButtonScaleX">-1</item>
</style>
+ <style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small">
+ <item name="android:background">@null</item>
+ </style>
+
<!-- Used to style charging animation AVD animation -->
<style name="ChargingAnim" />
@@ -692,14 +696,16 @@
<style name="Control" />
<style name="Control.MenuItem">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
- <item name="android:textSize">@dimen/control_text_size</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">@dimen/control_menu_item_text_size</item>
<item name="android:textColor">@color/control_primary_text</item>
<item name="android:singleLine">true</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:minHeight">@dimen/control_menu_item_min_height</item>
</style>
<style name="Control.Spinner">
- <item name="android:textSize">@dimen/control_header_text_size</item>
+ <item name="android:textColor">@color/control_primary_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
@@ -707,11 +713,12 @@
<style name="Control.Spinner.Header">
<item name="android:background">@drawable/control_spinner_background</item>
- <item name="android:textColor">@color/control_primary_text</item>
+ <item name="android:textSize">@dimen/control_header_text_size</item>
</style>
<style name="Control.Spinner.Item">
- <item name="android:textColor">@color/control_secondary_text</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">@dimen/control_item_text_size</item>
</style>
<style name="TextAppearance.Control.Status">
@@ -731,11 +738,24 @@
<item name="android:textSize">@dimen/control_text_size</item>
<item name="android:textColor">@color/control_secondary_text</item>
</style>
+ <style name="TextAppearance.Control.Management" >
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+ <style name="TextAppearance.Control.Management.Title">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textSize">@dimen/controls_title_size</item>
+ </style>
+ <style name="TextAppearance.Control.Management.Subtitle">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">@dimen/controls_subtitle_size</item>
+ </style>
+
<style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow">
<item name="android:overlapAnchor">true</item>
<!-- used to override dark/light theming -->
- <item name="*android:colorPopupBackground">@color/GM2_grey_900</item>
+ <item name="*android:colorBackgroundFloating">@color/GM2_grey_800</item>
+ <item name="*android:colorPopupBackground">@color/GM2_grey_800</item>
</style>
<style name="TextAppearance.ControlSetup">
@@ -752,6 +772,10 @@
<item name="android:textSize">16sp</item>
</style>
- <style name="Theme.ControlsRequestDialog" parent="@style/Theme.SystemUI.MediaProjectionAlertDialog"/>
+ <!-- The attributes used for title (textAppearanceLarge) and message (textAppearanceMedium)
+ are already as necessary:
+ * Title: headline, medium 20sp
+ * Message: body, 16 sp -->
+ <style name="Theme.ControlsRequestDialog" parent="@*android:style/Theme.DeviceDefault.Dialog.Alert"/>
</resources>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 592f6c2..68f4b746 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -38,9 +38,7 @@
"PluginCoreLib",
],
- // Enforce that the library is built against java 7 so that there are
- // no compatibility issues with launcher
- java_version: "1.7",
+ java_version: "1.8",
min_sdk_version: "26",
}
diff --git a/packages/SystemUI/shared/AndroidManifest.xml b/packages/SystemUI/shared/AndroidManifest.xml
index 43b9c75..aaadea6 100644
--- a/packages/SystemUI/shared/AndroidManifest.xml
+++ b/packages/SystemUI/shared/AndroidManifest.xml
@@ -18,7 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.systemui.shared">
- <uses-sdk
- android:minSdkVersion="26" />
</manifest>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 26ef1d6..0350f2d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -28,57 +28,6 @@
void onInitialize(in Bundle params) = 12;
/**
- * @deprecated
- */
- void onBind(in ISystemUiProxy sysUiProxy) = 0;
-
- /**
- * Called once immediately prior to the first onMotionEvent() call, providing a hint to the
- * target the initial source of the subsequent motion events.
- *
- * @param downHitTarget is one of the {@link NavigationBarCompat.HitTarget}s
- *
- * @deprecated
- */
- void onPreMotionEvent(int downHitTarget) = 1;
-
- /**
- * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
- * guarantees the following order of events:
- *
- * Normal gesture: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, UP
- * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
- *
- * Once quick scrub is sent, then no further motion events will be provided.
- *
- * @deprecated
- */
- void onMotionEvent(in MotionEvent event) = 2;
-
- /**
- * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
- * sent the caller will stop sending any motion events and will no longer preemptively cancel
- * any recents animations started as a part of the motion event handling.
- *
- * @deprecated
- */
- void onQuickScrubStart() = 3;
-
- /**
- * Sent when the user stops actively scrubbing the nav bar to switch tasks.
- *
- * @deprecated
- */
- void onQuickScrubEnd() = 4;
-
- /**
- * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
- *
- * @deprecated
- */
- void onQuickScrubProgress(float progress) = 5;
-
- /**
* Sent when overview button is pressed to toggle show/hide of overview.
*/
void onOverviewToggle() = 6;
@@ -94,22 +43,8 @@
void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) = 8;
/**
- * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
- * by passing the touch slop in the direction towards launcher from navigation bar. During and
- * after this event is sent the caller will continue to send motion events. The motion
- * {@param event} passed after the touch slop was exceeded will also be passed after by
- * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be
- * sent to cancel overview regardless the current state of launcher (eg. if overview is already
- * visible, this event will still be sent if user swipes up). When this signal is sent,
- * navigation bar will not handle any gestures such as quick scrub and the home button will
- * cancel (long) press.
- *
- * @deprecated
- */
- void onQuickStep(in MotionEvent event) = 9;
-
- /**
* Sent when there was an action on one of the onboarding tips view.
+ * TODO: Move this implementation to SystemUI completely
*/
void onTip(int actionType, int viewType) = 10;
@@ -125,6 +60,7 @@
/**
* Sent when back is triggered.
+ * TODO: Move this implementation to SystemUI completely
*/
void onBackAction(boolean completed, int downX, int downY, boolean isButton,
boolean gestureSwipeLeft) = 15;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java
index c2a4af9..acc6913 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java
@@ -20,6 +20,9 @@
import android.view.View;
import android.view.ViewRootImpl;
+/**
+ * TODO: Remove this class
+ */
public class SurfaceControlCompat {
final SurfaceControl mSurfaceControl;
@@ -37,4 +40,8 @@
public boolean isValid() {
return mSurfaceControl != null && mSurfaceControl.isValid();
}
+
+ public SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 2e6b195..31fe22e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -23,8 +23,8 @@
import android.os.Handler.Callback;
import android.os.Message;
import android.os.Trace;
-import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.ViewRootImpl;
@@ -108,13 +108,12 @@
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Sync transaction frameNumber=" + frame);
- TransactionCompat t = new TransactionCompat();
+ Transaction t = new Transaction();
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
- SurfaceControlCompat surface = surfaceParams.surface;
- t.deferTransactionUntil(surface, mBarrierSurfaceControl, frame);
- applyParams(t, surfaceParams);
+ t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
+ surfaceParams.applyTo(t);
}
t.setEarlyWakeup();
t.apply();
@@ -152,31 +151,7 @@
public static void applyParams(TransactionCompat t,
SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
- if ((params.flags & FLAG_MATRIX) != 0) {
- t.setMatrix(params.surface, params.matrix);
- }
- if ((params.flags & FLAG_WINDOW_CROP) != 0) {
- t.setWindowCrop(params.surface, params.windowCrop);
- }
- if ((params.flags & FLAG_ALPHA) != 0) {
- t.setAlpha(params.surface, params.alpha);
- }
- if ((params.flags & FLAG_LAYER) != 0) {
- t.setLayer(params.surface, params.layer);
- }
- if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
- t.setCornerRadius(params.surface, params.cornerRadius);
- }
- if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
- t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
- }
- if ((params.flags & FLAG_VISIBILITY) != 0) {
- if (params.visible) {
- t.show(params.surface);
- } else {
- t.hide(params.surface);
- }
- }
+ params.applyTo(t.mTransaction);
}
/**
@@ -210,7 +185,7 @@
public static class SurfaceParams {
public static class Builder {
- final SurfaceControlCompat surface;
+ final SurfaceControl surface;
int flags;
float alpha;
float cornerRadius;
@@ -224,6 +199,13 @@
* @param surface The surface to modify.
*/
public Builder(SurfaceControlCompat surface) {
+ this(surface.mSurfaceControl);
+ }
+
+ /**
+ * @param surface The surface to modify.
+ */
+ public Builder(SurfaceControl surface) {
this.surface = surface;
}
@@ -317,11 +299,12 @@
*/
public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
Rect windowCrop, int layer, float cornerRadius) {
- this(surface, FLAG_ALL & ~(FLAG_VISIBILITY | FLAG_BACKGROUND_BLUR_RADIUS), alpha,
+ this(surface.mSurfaceControl,
+ FLAG_ALL & ~(FLAG_VISIBILITY | FLAG_BACKGROUND_BLUR_RADIUS), alpha,
matrix, windowCrop, layer, cornerRadius, 0 /* backgroundBlurRadius */, true);
}
- private SurfaceParams(SurfaceControlCompat surface, int flags, float alpha, Matrix matrix,
+ private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius,
boolean visible) {
this.flags = flags;
@@ -336,8 +319,9 @@
}
private final int flags;
+ private final float[] mTmpValues = new float[9];
- public final SurfaceControlCompat surface;
+ public final SurfaceControl surface;
public final float alpha;
public final float cornerRadius;
public final int backgroundBlurRadius;
@@ -345,5 +329,33 @@
public final Rect windowCrop;
public final int layer;
public final boolean visible;
+
+ public void applyTo(SurfaceControl.Transaction t) {
+ if ((flags & FLAG_MATRIX) != 0) {
+ t.setMatrix(surface, matrix, mTmpValues);
+ }
+ if ((flags & FLAG_WINDOW_CROP) != 0) {
+ t.setWindowCrop(surface, windowCrop);
+ }
+ if ((flags & FLAG_ALPHA) != 0) {
+ t.setAlpha(surface, alpha);
+ }
+ if ((flags & FLAG_LAYER) != 0) {
+ t.setLayer(surface, layer);
+ }
+ if ((flags & FLAG_CORNER_RADIUS) != 0) {
+ t.setCornerRadius(surface, cornerRadius);
+ }
+ if ((flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
+ t.setBackgroundBlurRadius(surface, backgroundBlurRadius);
+ }
+ if ((flags & FLAG_VISIBILITY) != 0) {
+ if (visible) {
+ t.show(surface);
+ } else {
+ t.hide(surface);
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
index c1c91f7..bdb6c06 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
@@ -18,9 +18,8 @@
import android.graphics.Matrix;
import android.graphics.Rect;
-import android.view.Surface;
-import android.view.SurfaceControl.Transaction;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
public class TransactionCompat {
@@ -109,4 +108,13 @@
mTransaction.setColor(surfaceControl.mSurfaceControl, color);
return this;
}
+
+ public static void deferTransactionUntil(Transaction t, SurfaceControl surfaceControl,
+ SurfaceControl barrier, long frameNumber) {
+ t.deferTransactionUntil(surfaceControl, barrier, frameNumber);
+ }
+
+ public static void setEarlyWakeup(Transaction t) {
+ t.setEarlyWakeup();
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
new file mode 100644
index 0000000..dd61326
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.shared.system;
+
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import java.util.function.LongConsumer;
+
+/**
+ * Helper class to expose some ViewRoomImpl methods
+ */
+public class ViewRootImplCompat {
+
+ private final ViewRootImpl mViewRoot;
+
+ public ViewRootImplCompat(View view) {
+ mViewRoot = view == null ? null : view.getViewRootImpl();
+ }
+
+ public SurfaceControl getRenderSurfaceControl() {
+ return mViewRoot == null ? null : mViewRoot.getRenderSurfaceControl();
+ }
+
+ public SurfaceControl getSurfaceControl() {
+ return mViewRoot == null ? null : mViewRoot.getSurfaceControl();
+ }
+
+ public boolean isValid() {
+ return mViewRoot != null;
+ }
+
+ public View getView() {
+ return mViewRoot == null ? null : mViewRoot.getView();
+ }
+
+ public void registerRtFrameCallback(LongConsumer callback) {
+ if (mViewRoot != null) {
+ mViewRoot.registerRtFrameCallback(callback::accept);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 95e9c20..9d8c545 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -510,7 +510,7 @@
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof KeyguardSliceTextView) {
- ((KeyguardSliceTextView) child).setMaxWidth(width / childCount);
+ ((KeyguardSliceTextView) child).setMaxWidth(width / 3);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
index 284074e..3015710 100644
--- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -37,20 +37,22 @@
private val cameraManager: CameraManager,
private val cutoutProtectionPath: Path,
private val targetCameraId: String,
+ excludedPackages: String,
private val executor: Executor
) {
private var cutoutBounds = Rect()
+ private val excludedPackageIds: Set<String>
private val listeners = mutableListOf<CameraTransitionCallback>()
private val availabilityCallback: CameraManager.AvailabilityCallback =
object : CameraManager.AvailabilityCallback() {
- override fun onCameraAvailable(cameraId: String) {
+ override fun onCameraClosed(cameraId: String) {
if (targetCameraId == cameraId) {
notifyCameraInactive()
}
}
- override fun onCameraUnavailable(cameraId: String) {
- if (targetCameraId == cameraId) {
+ override fun onCameraOpened(cameraId: String, packageId: String) {
+ if (targetCameraId == cameraId && !isExcluded(packageId)) {
notifyCameraActive()
}
}
@@ -64,6 +66,7 @@
computed.top.roundToInt(),
computed.right.roundToInt(),
computed.bottom.roundToInt())
+ excludedPackageIds = excludedPackages.split(",").toSet()
}
/**
@@ -87,6 +90,10 @@
listeners.remove(callback)
}
+ private fun isExcluded(packageId: String): Boolean {
+ return excludedPackageIds.contains(packageId)
+ }
+
private fun registerCameraListener() {
cameraManager.registerAvailabilityCallback(executor, availabilityCallback)
}
@@ -118,9 +125,10 @@
val res = context.resources
val pathString = res.getString(R.string.config_frontBuiltInDisplayCutoutProtection)
val cameraId = res.getString(R.string.config_protectedCameraId)
+ val excluded = res.getString(R.string.config_cameraProtectionExcludedPackages)
return CameraAvailabilityListener(
- manager, pathFromString(pathString), cameraId, executor)
+ manager, pathFromString(pathString), cameraId, excluded, executor)
}
private fun pathFromString(pathString: String): Path {
@@ -135,4 +143,4 @@
return p
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 0af026e..02d2b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -76,7 +76,6 @@
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -308,7 +307,6 @@
@Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
@Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
@Inject Lazy<DockManager> mDockManager;
- @Inject Lazy<ChannelEditorDialogController> mChannelEditorDialogController;
@Inject Lazy<INotificationManager> mINotificationManager;
@Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
@Inject Lazy<AlarmManager> mAlarmManager;
@@ -498,7 +496,6 @@
mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
mProviders.put(DockManager.class, mDockManager::get);
- mProviders.put(ChannelEditorDialogController.class, mChannelEditorDialogController::get);
mProviders.put(INotificationManager.class, mINotificationManager::get);
mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get);
mProviders.put(AlarmManager.class, mAlarmManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 73dfd32..b727563 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -125,6 +125,9 @@
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER =
AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER; // 12
+ public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT =
+ AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT; // 13
+
private Recents mRecents;
private StatusBar mStatusBar;
private SystemActionsBroadcastReceiver mReceiver;
@@ -191,6 +194,10 @@
R.string.accessibility_system_action_screenshot_label,
SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT);
+ RemoteAction actionAccessibilityShortcut = createRemoteAction(
+ R.string.accessibility_system_action_hardware_a11y_shortcut_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
+
mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
@@ -199,6 +206,8 @@
mA11yManager.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG);
mA11yManager.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN);
mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT);
+ mA11yManager.registerSystemAction(
+ actionAccessibilityShortcut, SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT);
}
/**
@@ -242,13 +251,18 @@
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT;
break;
case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON:
- labelId = R.string.accessibility_system_action_accessibility_button_label;
+ labelId = R.string.accessibility_system_action_on_screen_a11y_shortcut_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON;
break;
case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER:
- labelId = R.string.accessibility_system_action_accessibility_button_chooser_label;
+ labelId =
+ R.string.accessibility_system_action_on_screen_a11y_shortcut_chooser_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER;
break;
+ case SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT:
+ labelId = R.string.accessibility_system_action_hardware_a11y_shortcut_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT;
+ break;
default:
return;
}
@@ -349,6 +363,10 @@
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
+ private void handleAccessibilityShortcut() {
+ mA11yManager.performAccessibilityShortcut();
+ }
+
private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -362,6 +380,8 @@
"SYSTEM_ACTION_ACCESSIBILITY_BUTTON";
private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER =
"SYSTEM_ACTION_ACCESSIBILITY_BUTTON_MENU";
+ private static final String INTENT_ACTION_ACCESSIBILITY_SHORTCUT =
+ "SYSTEM_ACTION_ACCESSIBILITY_SHORTCUT";
private PendingIntent createPendingIntent(Context context, String intentAction) {
switch (intentAction) {
@@ -374,7 +394,8 @@
case INTENT_ACTION_LOCK_SCREEN:
case INTENT_ACTION_TAKE_SCREENSHOT:
case INTENT_ACTION_ACCESSIBILITY_BUTTON:
- case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER: {
+ case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER:
+ case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: {
Intent intent = new Intent(intentAction);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
@@ -396,6 +417,7 @@
intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER);
+ intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
return intentFilter;
}
@@ -443,6 +465,10 @@
handleAccessibilityButtonChooser();
break;
}
+ case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: {
+ handleAccessibilityShortcut();
+ break;
+ }
default:
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 7dea7f8..7c25d28 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -432,7 +432,7 @@
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
}
- public void updateState(@BiometricState int newState) {
+ void updateState(@BiometricState int newState) {
Log.v(TAG, "newState: " + newState);
switch (newState) {
@@ -453,8 +453,10 @@
}
announceForAccessibility(getResources()
.getString(R.string.biometric_dialog_authenticated));
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
- getDelayAfterAuthenticatedDurationMs());
+ mHandler.postDelayed(() -> {
+ Log.d(TAG, "Sending ACTION_AUTHENTICATED");
+ mCallback.onAction(Callback.ACTION_AUTHENTICATED);
+ }, getDelayAfterAuthenticatedDurationMs());
break;
case STATE_PENDING_CONFIRMATION:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b736b4d..8608766 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -113,6 +113,7 @@
int mModalityMask;
boolean mSkipIntro;
long mOperationId;
+ int mSysUiSessionId;
}
public static class Builder {
@@ -158,6 +159,11 @@
return this;
}
+ public Builder setSysUiSessionId(int sysUiSessionId) {
+ mConfig.mSysUiSessionId = sysUiSessionId;
+ return this;
+ }
+
public AuthContainerView build(int modalityMask) {
mConfig.mModalityMask = modalityMask;
return new AuthContainerView(mConfig, new Injector());
@@ -203,6 +209,9 @@
final class BiometricCallback implements AuthBiometricView.Callback {
@Override
public void onAction(int action) {
+ Log.d(TAG, "onAction: " + action
+ + ", sysUiSessionId: " + mConfig.mSysUiSessionId
+ + ", state: " + mContainerState);
switch (action) {
case AuthBiometricView.Callback.ACTION_AUTHENTICATED:
animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
@@ -461,13 +470,13 @@
if (animate) {
animateAway(false /* sendReason */, 0 /* reason */);
} else {
- removeWindowIfAttached();
+ removeWindowIfAttached(false /* sendReason */);
}
}
@Override
public void dismissFromSystemServer() {
- removeWindowIfAttached();
+ removeWindowIfAttached(true /* sendReason */);
}
@Override
@@ -540,7 +549,7 @@
final Runnable endActionRunnable = () -> {
setVisibility(View.INVISIBLE);
- removeWindowIfAttached();
+ removeWindowIfAttached(true /* sendReason */);
};
postOnAnimation(() -> {
@@ -575,19 +584,24 @@
}
private void sendPendingCallbackIfNotNull() {
- Log.d(TAG, "pendingCallback: " + mPendingCallbackReason);
+ Log.d(TAG, "pendingCallback: " + mPendingCallbackReason
+ + " sysUISessionId: " + mConfig.mSysUiSessionId);
if (mPendingCallbackReason != null) {
mConfig.mCallback.onDismissed(mPendingCallbackReason, mCredentialAttestation);
mPendingCallbackReason = null;
}
}
- private void removeWindowIfAttached() {
- sendPendingCallbackIfNotNull();
+ private void removeWindowIfAttached(boolean sendReason) {
+ if (sendReason) {
+ sendPendingCallbackIfNotNull();
+ }
if (mContainerState == STATE_GONE) {
+ Log.w(TAG, "Container already STATE_GONE, mSysUiSessionId: " + mConfig.mSysUiSessionId);
return;
}
+ Log.d(TAG, "Removing container, mSysUiSessionId: " + mConfig.mSysUiSessionId);
mContainerState = STATE_GONE;
mWindowManager.removeView(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0c6794c..9f0ea3e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -276,14 +276,15 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
final int authenticators = Utils.getAuthenticators(bundle);
if (DEBUG) {
Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
+ ", biometricModality: " + biometricModality
+ ", requireConfirmation: " + requireConfirmation
- + ", operationId: " + operationId);
+ + ", operationId: " + operationId
+ + ", sysUiSessionId: " + sysUiSessionId);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -293,6 +294,7 @@
args.argi2 = userId;
args.arg4 = opPackageName;
args.arg5 = operationId;
+ args.argi3 = sysUiSessionId;
boolean skipAnimation = false;
if (mCurrentDialog != null) {
@@ -382,6 +384,7 @@
final int userId = args.argi2;
final String opPackageName = (String) args.arg4;
final long operationId = (long) args.arg5;
+ final int sysUiSessionId = args.argi3;
// Create a new dialog but do not replace the current one yet.
final AuthDialog newDialog = buildDialog(
@@ -391,7 +394,8 @@
type,
opPackageName,
skipAnimation,
- operationId);
+ operationId,
+ sysUiSessionId);
if (newDialog == null) {
Log.e(TAG, "Unsupported type: " + type);
@@ -403,7 +407,8 @@
+ " savedState: " + savedState
+ " mCurrentDialog: " + mCurrentDialog
+ " newDialog: " + newDialog
- + " type: " + type);
+ + " type: " + type
+ + " sysUiSessionId: " + sysUiSessionId);
}
if (mCurrentDialog != null) {
@@ -458,7 +463,8 @@
}
protected AuthDialog buildDialog(Bundle biometricPromptBundle, boolean requireConfirmation,
- int userId, int type, String opPackageName, boolean skipIntro, long operationId) {
+ int userId, int type, String opPackageName, boolean skipIntro, long operationId,
+ int sysUiSessionId) {
return new AuthContainerView.Builder(mContext)
.setCallback(this)
.setBiometricPromptBundle(biometricPromptBundle)
@@ -467,6 +473,7 @@
.setOpPackageName(opPackageName)
.setSkipIntro(skipIntro)
.setOperationId(operationId)
+ .setSysUiSessionId(sysUiSessionId)
.build(type);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 4e84f06..3272fb7 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -32,6 +32,8 @@
import com.android.systemui.Dumpable
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.lang.IllegalArgumentException
+import java.lang.IllegalStateException
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
@@ -211,7 +213,12 @@
*/
override fun run() {
if (registered.get()) {
- context.unregisterReceiver(this@UserBroadcastDispatcher)
+ try {
+ context.unregisterReceiver(this@UserBroadcastDispatcher)
+ } catch (e: IllegalArgumentException) {
+ Log.e(TAG, "Trying to unregister unregistered receiver for user $userId",
+ IllegalStateException(e))
+ }
registered.set(false)
}
// Short interval without receiver, this can be problematic
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 013f222..ad8d57b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -29,7 +29,7 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -53,7 +53,9 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -66,7 +68,7 @@
import android.util.SparseSetArray;
import android.view.Display;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.WindowManager;
import androidx.annotation.IntDef;
import androidx.annotation.MainThread;
@@ -76,7 +78,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.R;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -88,6 +89,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
+import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -98,6 +100,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -145,14 +148,15 @@
private final NotificationEntryManager mNotificationEntryManager;
private final NotifPipeline mNotifPipeline;
private final BubbleTaskStackListener mTaskStackListener;
- private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
private final NotificationGroupManager mNotificationGroupManager;
private final ShadeController mShadeController;
private final FloatingContentCoordinator mFloatingContentCoordinator;
+ private final BubbleDataRepository mDataRepository;
private BubbleData mBubbleData;
+ private ScrimView mBubbleScrim;
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
@@ -175,11 +179,16 @@
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
+ private WindowManager mWindowManager;
private SysUiState mSysUiState;
// Used to post to main UI thread
private Handler mHandler = new Handler();
+ /** LayoutParams used to add the BubbleStackView to the window maanger. */
+ private WindowManager.LayoutParams mWmLayoutParams;
+
+
// Used for determining view rect for touch interaction
private Rect mTempRect = new Rect();
@@ -195,16 +204,6 @@
private final List<NotifCallback> mCallbacks = new ArrayList<>();
/**
- * Listener to be notified when some states of the bubbles change.
- */
- public interface BubbleStateChangeListener {
- /**
- * Called when the stack has bubbles or no longer has bubbles.
- */
- void onHasBubblesChanged(boolean hasBubbles);
- }
-
- /**
* Listener to find out about stack expansion / collapse events.
*/
public interface BubbleExpandListener {
@@ -296,13 +295,14 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
+ BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager) {
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
data, null /* synchronizer */, configurationController, interruptionStateProvider,
zenModeController, notifUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
- notificationManager);
+ notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
+ dataRepository, sysUiState, notificationManager);
}
/**
@@ -324,6 +324,7 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
+ BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager) {
dumpManager.registerDumpable(TAG, this);
@@ -333,6 +334,7 @@
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
mFloatingContentCoordinator = floatingContentCoordinator;
+ mDataRepository = dataRepository;
mINotificationManager = notificationManager;
mZenModeController.addCallback(new ZenModeController.Callback() {
@Override
@@ -393,9 +395,12 @@
}
mSurfaceSynchronizer = synchronizer;
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mBubbleScrim = new ScrimView(mContext);
+
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mCurrentUserId = mNotifUserManager.getCurrentUserId();
mNotifUserManager.addUserChangedListener(
@@ -573,6 +578,15 @@
}
/**
+ * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
+ * since we want the scrim's appearance and behavior to be identical to that of the notification
+ * shade scrim.
+ */
+ public ScrimView getScrimForBubble() {
+ return mBubbleScrim;
+ }
+
+ /**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
*/
@@ -592,7 +606,6 @@
return mBubbleData.getOverflowBubbles();
}
-
/**
* BubbleStackView is lazily created by this method the first time a Bubble is added. This
* method initializes the stack view and adds it to the StatusBar just above the scrim.
@@ -602,11 +615,8 @@
mStackView = new BubbleStackView(
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
mSysUiState, mNotificationShadeWindowController);
- ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView();
- int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble));
- int stackIndex = bubbleScrimIndex + 1; // Show stack above bubble scrim.
- nsv.addView(mStackView, stackIndex,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mStackView.addView(mBubbleScrim);
+ addToWindowManager();
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
}
@@ -616,6 +626,45 @@
}
}
+ /** Adds the BubbleStackView to the WindowManager. */
+ private void addToWindowManager() {
+ mWmLayoutParams = new WindowManager.LayoutParams(
+ // Fill the screen so we can use translation animations to position the bubble
+ // stack. We'll use touchable regions to ignore touches that are not on the bubbles
+ // themselves.
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ // Start not focusable - we'll become focusable when expanded so the ActivityView
+ // can use the IME.
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ PixelFormat.TRANSLUCENT);
+
+ mWmLayoutParams.setFitInsetsTypes(0);
+ mWmLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+ mWmLayoutParams.token = new Binder();
+ mWmLayoutParams.setTitle("Bubbles!");
+ mWmLayoutParams.packageName = mContext.getPackageName();
+ mWmLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+ mWindowManager.addView(mStackView, mWmLayoutParams);
+ }
+
+ private void updateWmFlags() {
+ if (isStackExpanded()) {
+ // If we're expanded, we want to be focusable so that the ActivityView can receive focus
+ // and show the IME.
+ mWmLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ } else {
+ // If we're collapsed, we don't want to be able to receive focus. Doing so would
+ // preclude applications from using the IME since we are always above them.
+ mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ }
+
+ mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ }
+
/**
* Records the notification key for any active bubbles. These are used to restore active
* bubbles when the user returns to the foreground.
@@ -687,13 +736,6 @@
}
/**
- * Set a listener to be notified when some states of the bubbles change.
- */
- public void setBubbleStateChangeListener(BubbleStateChangeListener listener) {
- mStateChangeListener = listener;
- }
-
- /**
* Set a listener to be notified of bubble expand events.
*/
public void setExpandListener(BubbleExpandListener listener) {
@@ -701,7 +743,8 @@
if (listener != null) {
listener.onBubbleExpandChanged(isExpanding, key);
}
- mNotificationShadeWindowController.setBubbleExpanded(isExpanding);
+
+ updateWmFlags();
});
if (mStackView != null) {
mStackView.setExpandListener(mExpandListener);
@@ -712,7 +755,8 @@
* Whether or not there are bubbles present, regardless of them being visible on the
* screen (e.g. if on AOD).
*/
- public boolean hasBubbles() {
+ @VisibleForTesting
+ boolean hasBubbles() {
if (mStackView == null) {
return false;
}
@@ -978,6 +1022,7 @@
// Do removals, if any.
ArrayList<Pair<Bubble, Integer>> removedBubbles =
new ArrayList<>(update.removedBubbles);
+ ArrayList<Bubble> bubblesToBeRemovedFromRepository = new ArrayList<>();
for (Pair<Bubble, Integer> removed : removedBubbles) {
final Bubble bubble = removed.first;
@DismissReason final int reason = removed.second;
@@ -987,6 +1032,9 @@
if (reason == DISMISS_USER_CHANGED) {
continue;
}
+ if (reason == DISMISS_NOTIF_CANCEL) {
+ bubblesToBeRemovedFromRepository.add(bubble);
+ }
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
&& (!bubble.showInShade()
@@ -1016,9 +1064,12 @@
}
}
}
+ mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
if (update.addedBubble != null) {
+ mDataRepository.addBubble(mCurrentUserId, update.addedBubble);
mStackView.addBubble(update.addedBubble);
+
}
if (update.updatedBubble != null) {
@@ -1028,6 +1079,7 @@
// At this point, the correct bubbles are inflated in the stack.
// Make sure the order in bubble data is reflected in bubble row.
if (update.orderChanged) {
+ mDataRepository.addBubbles(mCurrentUserId, update.bubbles);
mStackView.updateBubbleOrder(update.bubbles);
}
@@ -1146,8 +1198,7 @@
/**
* Lets any listeners know if bubble state has changed.
* Updates the visibility of the bubbles based on current state.
- * Does not un-bubble, just hides or un-hides. Notifies any
- * {@link BubbleStateChangeListener}s of visibility changes.
+ * Does not un-bubble, just hides or un-hides.
* Updates stack description for TalkBack focus.
*/
public void updateStack() {
@@ -1161,29 +1212,10 @@
mStackView.setVisibility(INVISIBLE);
}
- // Let listeners know if bubble state changed.
- boolean hadBubbles = mNotificationShadeWindowController.getBubblesShowing();
- boolean hasBubblesShowing = hasBubbles() && mStackView.getVisibility() == VISIBLE;
- mNotificationShadeWindowController.setBubblesShowing(hasBubblesShowing);
- if (mStateChangeListener != null && hadBubbles != hasBubblesShowing) {
- mStateChangeListener.onHasBubblesChanged(hasBubblesShowing);
- }
-
mStackView.updateContentDescription();
}
/**
- * Rect indicating the touchable region for the bubble stack / expanded stack.
- */
- public Rect getTouchableRegion() {
- if (mStackView == null || mStackView.getVisibility() != VISIBLE) {
- return null;
- }
- mStackView.getBoundsOnScreen(mTempRect);
- return mTempRect;
- }
-
- /**
* The display id of the expanded view, if the stack is expanded and not occluded by the
* status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
new file mode 100644
index 0000000..b9825e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles
+
+import android.annotation.UserIdInt
+import android.util.Log
+import com.android.systemui.bubbles.storage.BubblePersistentRepository
+import com.android.systemui.bubbles.storage.BubbleVolatileRepository
+import com.android.systemui.bubbles.storage.BubbleXmlEntity
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.yield
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+internal class BubbleDataRepository @Inject constructor(
+ private val volatileRepository: BubbleVolatileRepository,
+ private val persistentRepository: BubblePersistentRepository
+) {
+
+ private val ioScope = CoroutineScope(Dispatchers.IO)
+ private val uiScope = CoroutineScope(Dispatchers.Main)
+ private var job: Job? = null
+
+ /**
+ * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
+ * asynchronously.
+ */
+ fun addBubble(@UserIdInt userId: Int, bubble: Bubble) = addBubbles(userId, listOf(bubble))
+
+ /**
+ * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
+ * asynchronously.
+ */
+ fun addBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
+ if (DEBUG) Log.d(TAG, "adding ${bubbles.size} bubbles")
+ val entities = transform(userId, bubbles).also(volatileRepository::addBubbles)
+ if (entities.isNotEmpty()) persistToDisk()
+ }
+
+ /**
+ * Removes the bubbles from memory, then persists the snapshot to disk asynchronously.
+ */
+ fun removeBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
+ if (DEBUG) Log.d(TAG, "removing ${bubbles.size} bubbles")
+ val entities = transform(userId, bubbles).also(volatileRepository::removeBubbles)
+ if (entities.isNotEmpty()) persistToDisk()
+ }
+
+ private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleXmlEntity> {
+ return bubbles.mapNotNull { b ->
+ val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null
+ BubbleXmlEntity(userId, b.packageName, shortcutId)
+ }
+ }
+
+ /**
+ * Persists the bubbles to disk. When being called multiple times, it waits for first ongoing
+ * write operation to finish then run another write operation exactly once.
+ *
+ * e.g.
+ * Job A started -> blocking I/O
+ * Job B started, cancels A, wait for blocking I/O in A finishes
+ * Job C started, cancels B, wait for job B to finish
+ * Job D started, cancels C, wait for job C to finish
+ * Job A completed
+ * Job B resumes and reaches yield() and is then cancelled
+ * Job C resumes and reaches yield() and is then cancelled
+ * Job D resumes and performs another blocking I/O
+ */
+ private fun persistToDisk() {
+ val prev = job
+ job = ioScope.launch {
+ // if there was an ongoing disk I/O operation, they can be cancelled
+ prev?.cancelAndJoin()
+ // check for cancellation before disk I/O
+ yield()
+ // save to disk
+ persistentRepository.persistsToDisk(volatileRepository.bubbles)
+ }
+ }
+
+ /**
+ * Load bubbles from disk.
+ */
+ fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
+ val bubbleXmlEntities = persistentRepository.readFromDisk()
+ volatileRepository.addBubbles(bubbleXmlEntities)
+ uiScope.launch {
+ // TODO: transform bubbleXmlEntities into bubbles
+ // cb(bubbles)
+ }
+ }
+}
+
+private const val TAG = "BubbleDataRepository"
+private const val DEBUG = false
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index bb23655..baf92dc 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -19,9 +19,15 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.graphics.PixelFormat.TRANSPARENT;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.sNewInsetsMode;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -42,12 +48,16 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
+import android.hardware.display.VirtualDisplay;
+import android.os.Binder;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
import com.android.internal.policy.ScreenDecorationsUtils;
@@ -62,6 +72,7 @@
*/
public class BubbleExpandedView extends LinearLayout {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleExpandedView" : TAG_BUBBLES;
+ private static final String WINDOW_TITLE = "ImeInsetsWindowWithoutContent";
private enum ActivityViewStatus {
// ActivityView is being initialized, cannot start an activity yet.
@@ -107,6 +118,9 @@
private WindowManager mWindowManager;
private BubbleStackView mStackView;
+ private View mVirtualImeView;
+ private WindowManager mVirtualDisplayWindowManager;
+ private boolean mImeShowing = false;
private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
@Override
@@ -131,6 +145,7 @@
}
try {
if (!mIsOverflow && mBubble.usingShortcutInfo()) {
+ options.setApplyActivityFlagsForBubbles(true);
mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
options, null /* sourceBounds */);
} else {
@@ -316,11 +331,8 @@
mKeyboardVisible = false;
mNeedsNewHeight = false;
if (mActivityView != null) {
- // TODO: Temporary hack to offset the view until we can properly inset Bubbles again.
if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- mStackView.animate()
- .setDuration(100)
- .translationY(0);
+ setImeWindowToDisplay(0, 0);
} else {
mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
}
@@ -364,18 +376,61 @@
: 0);
final int insetsBottom = Math.max(activityViewBottom - keyboardTop, 0);
- // TODO: Temporary hack to offset the view until we can properly inset Bubbles again.
if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- mStackView.animate()
- .setDuration(100)
- .translationY(-insetsBottom)
- .withEndAction(() -> mActivityView.onLocationChanged());
+ setImeWindowToDisplay(getWidth(), insetsBottom);
} else {
mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
}
}
}
+ private void setImeWindowToDisplay(int w, int h) {
+ if (getVirtualDisplayId() == INVALID_DISPLAY) {
+ return;
+ }
+ if (h == 0 || w == 0) {
+ if (mImeShowing) {
+ mVirtualImeView.setVisibility(GONE);
+ mImeShowing = false;
+ }
+ return;
+ }
+ final Context virtualDisplayContext = mContext.createDisplayContext(
+ getVirtualDisplay().getDisplay());
+
+ if (mVirtualDisplayWindowManager == null) {
+ mVirtualDisplayWindowManager =
+ (WindowManager) virtualDisplayContext.getSystemService(Context.WINDOW_SERVICE);
+ }
+ if (mVirtualImeView == null) {
+ mVirtualImeView = new View(virtualDisplayContext);
+ mVirtualImeView.setVisibility(VISIBLE);
+ mVirtualDisplayWindowManager.addView(mVirtualImeView,
+ getVirtualImeViewAttrs(w, h));
+ } else {
+ mVirtualDisplayWindowManager.updateViewLayout(mVirtualImeView,
+ getVirtualImeViewAttrs(w, h));
+ mVirtualImeView.setVisibility(VISIBLE);
+ }
+
+ mImeShowing = true;
+ }
+
+ private WindowManager.LayoutParams getVirtualImeViewAttrs(int w, int h) {
+ // To use TYPE_NAVIGATION_BAR_PANEL instead of TYPE_IME_BAR to bypass the IME window type
+ // token check when adding the window.
+ final WindowManager.LayoutParams attrs =
+ new WindowManager.LayoutParams(w, h, TYPE_NAVIGATION_BAR_PANEL,
+ FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE,
+ TRANSPARENT);
+ attrs.gravity = Gravity.BOTTOM;
+ attrs.setTitle(WINDOW_TITLE);
+ attrs.token = new Binder();
+ attrs.providesInsetsTypes = new int[]{ITYPE_IME};
+ attrs.alpha = 0.0f;
+ return attrs;
+ }
+
void setStackView(BubbleStackView stackView) {
mStackView = stackView;
}
@@ -402,6 +457,19 @@
mSettingsIcon.setContentDescription(getResources().getString(
R.string.bubbles_settings_button_description, bubble.getAppName()));
+ mSettingsIcon.setAccessibilityDelegate(
+ new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // On focus, have TalkBack say
+ // "Actions available. Use swipe up then right to view."
+ // in addition to the default "double tap to activate".
+ mStackView.setupLocalMenu(info);
+ }
+ });
+
if (isNew) {
mPendingIntent = mBubble.getBubbleIntent();
if (mPendingIntent != null || mBubble.getShortcutInfo() != null) {
@@ -569,4 +637,11 @@
}
return INVALID_DISPLAY;
}
+
+ private VirtualDisplay getVirtualDisplay() {
+ if (usingActivityView()) {
+ return mActivityView.getVirtualDisplay();
+ }
+ return null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index 13669a6..e96bef3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -73,12 +73,13 @@
updateIcon(mContext, parentViewGroup);
}
- // TODO(b/149146374) Propagate theme change to bubbles in overflow.
void updateIcon(Context context, ViewGroup parentViewGroup) {
mInflater = LayoutInflater.from(context);
mOverflowBtn = (BadgedImageView) mInflater.inflate(R.layout.bubble_overflow_button,
parentViewGroup /* root */,
false /* attachToRoot */);
+ mOverflowBtn.setContentDescription(mContext.getResources().getString(
+ R.string.bubble_overflow_button_content_description));
TypedArray ta = mContext.obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index de54c35..c2ca9fa 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -21,6 +21,7 @@
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
+import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -32,6 +33,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -103,7 +105,7 @@
- res.getDimensionPixelSize(R.dimen.bubble_overflow_padding);
final int viewHeight = recyclerViewHeight / rows;
- mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
+ mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles,
mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight);
mRecyclerView.setAdapter(mAdapter);
@@ -221,13 +223,15 @@
}
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
+ private Context mContext;
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
private int mWidth;
private int mHeight;
- public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble, int width,
- int height) {
+ public BubbleOverflowAdapter(Context context, List<Bubble> list, Consumer<Bubble> promoteBubble,
+ int width, int height) {
+ mContext = context;
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
mWidth = width;
@@ -260,6 +264,32 @@
mPromoteBubbleFromOverflow.accept(b);
});
+ final CharSequence titleCharSeq =
+ b.getEntry().getSbn().getNotification().extras.getCharSequence(
+ Notification.EXTRA_TITLE);
+ String titleStr = mContext.getResources().getString(R.string.notification_bubble_title);
+ if (titleCharSeq != null) {
+ titleStr = titleCharSeq.toString();
+ }
+ vh.iconView.setContentDescription(mContext.getResources().getString(
+ R.string.bubble_content_description_single, titleStr, b.getAppName()));
+
+ vh.iconView.setAccessibilityDelegate(
+ new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // Talkback prompts "Double tap to add back to stack"
+ // instead of the default "Double tap to activate"
+ info.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ mContext.getResources().getString(
+ R.string.bubble_accessibility_action_add_back)));
+ }
+ });
+
Bubble.FlyoutMessage message = b.getFlyoutMessage();
if (message != null && message.senderName != null) {
vh.textView.setText(message.senderName);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 366d4a7..2cb097f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -108,7 +108,8 @@
/**
* Renders bubbles in a stack and handles animating expanded and collapsed states.
*/
-public class BubbleStackView extends FrameLayout {
+public class BubbleStackView extends FrameLayout
+ implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
/** Animation durations for bubble stack user education views. **/
@@ -453,7 +454,6 @@
// that means overflow was previously expanded. Set the selected bubble
// internally without going through BubbleData (which would ignore it since it's
// already selected).
- mBubbleData.setShowingOverflow(true);
setSelectedBubble(clickedBubble);
}
} else {
@@ -464,6 +464,7 @@
mBubbleData.setExpanded(!mBubbleData.isExpanded());
}
}
+ mExpandedAnimationController.onGestureFinished();
}
};
@@ -647,7 +648,6 @@
private boolean mShowingManage = false;
private PhysicsAnimator.SpringConfig mManageSpringConfig = new PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
-
@SuppressLint("ClickableViewAccessibility")
public BubbleStackView(Context context, BubbleData data,
@Nullable SurfaceSynchronizer synchronizer,
@@ -1052,39 +1052,50 @@
}
@Override
- public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
- getBoundsOnScreen(outRect);
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+ inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+ getTouchableRegion(mTempRect);
+ inoutInfo.touchableRegion.set(mTempRect);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
}
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
+ setupLocalMenu(info);
+ }
- // Custom actions.
+ void setupLocalMenu(AccessibilityNodeInfo info) {
+ Resources res = mContext.getResources();
+
+ // Custom local actions.
AccessibilityAction moveTopLeft = new AccessibilityAction(R.id.action_move_top_left,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_top_left));
+ res.getString(R.string.bubble_accessibility_action_move_top_left));
info.addAction(moveTopLeft);
AccessibilityAction moveTopRight = new AccessibilityAction(R.id.action_move_top_right,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_top_right));
+ res.getString(R.string.bubble_accessibility_action_move_top_right));
info.addAction(moveTopRight);
AccessibilityAction moveBottomLeft = new AccessibilityAction(R.id.action_move_bottom_left,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_bottom_left));
+ res.getString(R.string.bubble_accessibility_action_move_bottom_left));
info.addAction(moveBottomLeft);
AccessibilityAction moveBottomRight = new AccessibilityAction(R.id.action_move_bottom_right,
- getContext().getResources()
- .getString(R.string.bubble_accessibility_action_move_bottom_right));
+ res.getString(R.string.bubble_accessibility_action_move_bottom_right));
info.addAction(moveBottomRight);
// Default actions.
@@ -1332,7 +1343,10 @@
}
if (bubbleToSelect == null || bubbleToSelect.getKey() != BubbleOverflow.KEY) {
mBubbleData.setShowingOverflow(false);
+ } else {
+ mBubbleData.setShowingOverflow(true);
}
+
final BubbleViewProvider previouslySelected = mExpandedBubble;
mExpandedBubble = bubbleToSelect;
updatePointerPosition();
@@ -1960,8 +1974,16 @@
mAfterFlyoutHidden = null;
}
- @Override
- public void getBoundsOnScreen(Rect outRect) {
+ /**
+ * Fills the Rect with the touchable region of the bubbles. This will be used by WindowManager
+ * to decide which touch events go to Bubbles.
+ *
+ * Bubbles is below the status bar/notification shade but above application windows. If you're
+ * trying to get touch events from the status bar or another higher-level window layer, you'll
+ * need to re-order TYPE_BUBBLES in WindowManagerPolicy so that we have the opportunity to steal
+ * them.
+ */
+ public void getTouchableRegion(Rect outRect) {
if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
// When user education shows then capture all touches
outRect.set(0, 0, getWidth(), getHeight());
@@ -1971,12 +1993,12 @@
if (!mIsExpanded) {
if (getBubbleCount() > 0) {
mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
+ // Increase the touch target size of the bubble
+ outRect.top -= mBubbleTouchPadding;
+ outRect.left -= mBubbleTouchPadding;
+ outRect.right += mBubbleTouchPadding;
+ outRect.bottom += mBubbleTouchPadding;
}
- // Increase the touch target size of the bubble
- outRect.top -= mBubbleTouchPadding;
- outRect.left -= mBubbleTouchPadding;
- outRect.right += mBubbleTouchPadding;
- outRect.bottom += mBubbleTouchPadding;
} else {
mBubbleContainer.getBoundsOnScreen(outRect);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 72d646e..e3b630b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -21,6 +21,7 @@
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubbleData;
+import com.android.systemui.bubbles.BubbleDataRepository;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -65,6 +66,7 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
+ BubbleDataRepository bubbleDataRepository,
SysUiState sysUiState,
INotificationManager notifManager) {
return new BubbleController(
@@ -84,6 +86,7 @@
featureFlags,
dumpManager,
floatingContentCoordinator,
+ bubbleDataRepository,
sysUiState,
notifManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
new file mode 100644
index 0000000..149e2c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles.storage
+
+import android.content.Context
+import android.util.AtomicFile
+import android.util.Log
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class BubblePersistentRepository @Inject constructor(
+ context: Context
+) {
+
+ private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir,
+ "overflow_bubbles.xml"), "overflow-bubbles")
+
+ fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean {
+ if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles")
+ synchronized(bubbleFile) {
+ val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) {
+ Log.e(TAG, "Failed to save bubble file", e)
+ return false
+ }
+ try {
+ writeXml(stream, bubbles)
+ bubbleFile.finishWrite(stream)
+ if (DEBUG) Log.d(TAG, "persisted ${bubbles.size} bubbles")
+ return true
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to save bubble file, restoring backup", e)
+ bubbleFile.failWrite(stream)
+ }
+ }
+ return false
+ }
+
+ fun readFromDisk(): List<BubbleXmlEntity> {
+ synchronized(bubbleFile) {
+ try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) {
+ Log.e(TAG, "Failed to open bubble file", e)
+ }
+ return emptyList()
+ }
+ }
+}
+
+private const val TAG = "BubblePersistentRepository"
+private const val DEBUG = false
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
new file mode 100644
index 0000000..e1f675b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles.storage
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val CAPACITY = 16
+
+/**
+ * BubbleVolatileRepository holds the most updated snapshot of list of bubbles for in-memory
+ * manipulation.
+ */
+@Singleton
+class BubbleVolatileRepository @Inject constructor() {
+ /**
+ * An ordered set of bubbles based on their natural ordering.
+ */
+ private val entities = mutableSetOf<BubbleXmlEntity>()
+
+ /**
+ * Returns a snapshot of all the bubbles.
+ */
+ val bubbles: List<BubbleXmlEntity>
+ @Synchronized
+ get() = entities.toList()
+
+ /**
+ * Add the bubbles to memory and perform a de-duplication. In case a bubble already exists,
+ * it will be moved to the last.
+ */
+ @Synchronized
+ fun addBubbles(bubbles: List<BubbleXmlEntity>) {
+ if (bubbles.isEmpty()) return
+ bubbles.forEach { entities.remove(it) }
+ if (entities.size + bubbles.size >= CAPACITY) {
+ entities.drop(entities.size + bubbles.size - CAPACITY)
+ }
+ entities.addAll(bubbles)
+ }
+
+ @Synchronized
+ fun removeBubbles(bubbles: List<BubbleXmlEntity>) {
+ bubbles.forEach { entities.remove(it) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
new file mode 100644
index 0000000..d0f7607
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles.storage
+
+import android.annotation.UserIdInt
+
+data class BubbleXmlEntity(
+ @UserIdInt val userId: Int,
+ val packageName: String,
+ val shortcutId: String
+)
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
new file mode 100644
index 0000000..1e91653
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles.storage
+
+import com.android.internal.util.FastXmlSerializer
+import org.xmlpull.v1.XmlSerializer
+import java.io.IOException
+import android.util.Xml
+import com.android.internal.util.XmlUtils
+import org.xmlpull.v1.XmlPullParser
+import java.io.InputStream
+import java.io.OutputStream
+import java.nio.charset.StandardCharsets
+
+private const val TAG_BUBBLES = "bs"
+private const val TAG_BUBBLE = "bb"
+private const val ATTR_USER_ID = "uid"
+private const val ATTR_PACKAGE = "pkg"
+private const val ATTR_SHORTCUT_ID = "sid"
+
+/**
+ * Writes the bubbles in xml format into given output stream.
+ */
+@Throws(IOException::class)
+fun writeXml(stream: OutputStream, bubbles: List<BubbleXmlEntity>) {
+ val serializer: XmlSerializer = FastXmlSerializer()
+ serializer.setOutput(stream, StandardCharsets.UTF_8.name())
+ serializer.startDocument(null, true)
+ serializer.startTag(null, TAG_BUBBLES)
+ bubbles.forEach { b -> writeXmlEntry(serializer, b) }
+ serializer.endTag(null, TAG_BUBBLES)
+ serializer.endDocument()
+}
+
+/**
+ * Creates a xml entry for given bubble in following format:
+ * ```
+ * <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" />
+ * ```
+ */
+private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) {
+ try {
+ serializer.startTag(null, TAG_BUBBLE)
+ serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString())
+ serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
+ serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
+ serializer.endTag(null, TAG_BUBBLE)
+ } catch (e: IOException) {
+ throw RuntimeException(e)
+ }
+}
+
+/**
+ * Reads the bubbles from xml file.
+ */
+fun readXml(stream: InputStream): List<BubbleXmlEntity> {
+ val bubbles = mutableListOf<BubbleXmlEntity>()
+ val parser: XmlPullParser = Xml.newPullParser()
+ parser.setInput(stream, StandardCharsets.UTF_8.name())
+ XmlUtils.beginDocument(parser, TAG_BUBBLES)
+ val outerDepth = parser.depth
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ bubbles.add(readXmlEntry(parser) ?: continue)
+ }
+ return bubbles
+}
+
+private fun readXmlEntry(parser: XmlPullParser): BubbleXmlEntity? {
+ while (parser.eventType != XmlPullParser.START_TAG) { parser.next() }
+ return BubbleXmlEntity(
+ parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
+ parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
+ parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null
+ )
+}
+
+private fun XmlPullParser.getAttributeWithName(name: String): String? {
+ for (i in 0 until attributeCount) {
+ if (getAttributeName(i) == name) return getAttributeValue(i)
+ }
+ return null
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index bc97c10..8196a25 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -23,7 +23,6 @@
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.UserAwareController
import com.android.systemui.controls.management.ControlsFavoritingActivity
-import com.android.systemui.controls.ui.ControlWithState
import com.android.systemui.controls.ui.ControlsUiController
import java.util.function.Consumer
@@ -110,13 +109,6 @@
@ControlAction.ResponseResult response: Int
)
- /**
- * When a control should be highlighted, dimming down what's around it.
- *
- * @param cws focused control, or {@code null} if nothing should be highlighted.
- */
- fun onFocusChanged(cws: ControlWithState?)
-
// FAVORITE MANAGEMENT
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 8e88756..a1f4c96 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -41,7 +41,6 @@
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
-import com.android.systemui.controls.ui.ControlWithState
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
@@ -149,6 +148,7 @@
val user = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL)
if (user == currentUserId) {
executor.execute {
+ Log.d(TAG, "Restore finished, storing auxiliary favorites")
auxiliaryPersistenceWrapper.initialize()
listingController.removeCallback(listingCallback)
persistenceWrapper.storeFavorites(auxiliaryPersistenceWrapper.favorites)
@@ -219,6 +219,7 @@
// Check if something has been added or removed, if so, store the new list
if (changed) {
+ Log.d(TAG, "Detected change in available services, storing updated favorites")
persistenceWrapper.storeFavorites(Favorites.getAllStructures())
}
}
@@ -498,10 +499,6 @@
}
}
- override fun onFocusChanged(cws: ControlWithState?) {
- uiController.onFocusChanged(cws)
- }
-
override fun refreshStatus(componentName: ComponentName, control: Control) {
if (!confirmAvailability()) {
Log.d(TAG, "Controls not available")
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
index cde258a0..1bda841 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
@@ -25,6 +25,7 @@
import libcore.io.IoUtils
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
+import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
@@ -152,7 +153,7 @@
return emptyList()
}
val reader = try {
- FileInputStream(file)
+ BufferedInputStream(FileInputStream(file))
} catch (fnfe: FileNotFoundException) {
Log.i(TAG, "No file found")
return emptyList()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 03ca393..79dd9ed 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -18,6 +18,7 @@
import android.content.ComponentName
import android.graphics.Rect
+import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.view.LayoutInflater
import android.view.View
@@ -46,9 +47,9 @@
) : RecyclerView.Adapter<Holder>() {
companion object {
- private const val TYPE_ZONE = 0
- private const val TYPE_CONTROL = 1
- private const val TYPE_DIVIDER = 2
+ const val TYPE_ZONE = 0
+ const val TYPE_CONTROL = 1
+ const val TYPE_DIVIDER = 2
}
val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
@@ -142,7 +143,7 @@
/**
* Holder for using with [DividerWrapper] to display a divider between zones.
*
- * The divider can be shown or hidden. It also has a frame view the height of a control, that can
+ * The divider can be shown or hidden. It also has a view the height of a control, that can
* be toggled visible or gone.
*/
private class DividerHolder(view: View) : Holder(view) {
@@ -229,10 +230,25 @@
parent: RecyclerView,
state: RecyclerView.State
) {
- outRect.apply {
- top = topMargin
- left = sideMargins
- right = sideMargins
+ val position = parent.getChildAdapterPosition(view)
+ if (position == RecyclerView.NO_POSITION) return
+ val type = parent.adapter?.getItemViewType(position)
+ if (type == ControlAdapter.TYPE_CONTROL) {
+ outRect.apply {
+ top = topMargin
+ left = sideMargins
+ right = sideMargins
+ bottom = 0
+ }
+ } else if (type == ControlAdapter.TYPE_ZONE && position == 0) {
+ // add negative padding to the first zone to counteract the margin
+ val margin = (view.layoutParams as ViewGroup.MarginLayoutParams).topMargin
+ outRect.apply {
+ top = -margin
+ left = 0
+ right = 0
+ bottom = 0
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index e3175aa..eb15262 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -104,7 +104,9 @@
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
if (serviceInfos.size > 1) {
- otherAppsButton.visibility = View.VISIBLE
+ otherAppsButton.post {
+ otherAppsButton.visibility = View.VISIBLE
+ }
}
}
}
@@ -122,7 +124,7 @@
val collator = Collator.getInstance(resources.configuration.locales[0])
comparator = compareBy(collator) { it.structureName }
appName = intent.getCharSequenceExtra(EXTRA_APP)
- structureExtra = intent.getCharSequenceExtra(EXTRA_STRUCTURE) ?: ""
+ structureExtra = intent.getCharSequenceExtra(EXTRA_STRUCTURE)
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
fromProviderSelector = intent.getBooleanExtra(EXTRA_FROM_PROVIDER_SELECTOR, false)
@@ -170,7 +172,7 @@
pageIndicator.setNumPages(listOfStructures.size)
pageIndicator.setLocation(0f)
pageIndicator.visibility =
- if (listOfStructures.size > 1) View.VISIBLE else View.GONE
+ if (listOfStructures.size > 1) View.VISIBLE else View.INVISIBLE
ControlsAnimations.enterAnimation(pageIndicator).apply {
addListener(object : AnimatorListenerAdapter() {
@@ -204,7 +206,9 @@
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
val name = listOfStructures[position].structureName
- titleView.text = if (!TextUtils.isEmpty(name)) name else appName
+ val title = if (!TextUtils.isEmpty(name)) name else appName
+ titleView.text = title
+ setTitle(title)
}
override fun onPageScrolled(
@@ -259,7 +263,6 @@
val title = structureExtra
?: (appName ?: resources.getText(R.string.controls_favorite_default_title))
- setTitle(title)
titleView = requireViewById<TextView>(R.id.title).apply {
text = title
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 94487e5..48f191d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -39,6 +39,7 @@
setNoun("Controls Provider")
setSetting("controls_providers")
setTag("controls_providers")
+ setAddDeviceLockedFlags(true)
}.build()
}
@@ -65,28 +66,39 @@
)
private var serviceListing = serviceListingBuilder(context)
+ // All operations in background thread
+ private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>()
companion object {
private const val TAG = "ControlsListingControllerImpl"
}
+ private var availableComponents = emptySet<ComponentName>()
private var availableServices = emptyList<ServiceInfo>()
override var currentUserId = ActivityManager.getCurrentUser()
private set
private val serviceListingCallback = ServiceListing.Callback {
- Log.d(TAG, "ServiceConfig reloaded")
- availableServices = it.toList()
+ val newServices = it.toList()
+ val newComponents =
+ newServices.mapTo(mutableSetOf<ComponentName>(), { s -> s.getComponentName() })
backgroundExecutor.execute {
- callbacks.forEach {
- it.onServicesUpdated(getCurrentServices())
+ if (!newComponents.equals(availableComponents)) {
+ Log.d(TAG, "ServiceConfig reloaded, count: ${newComponents.size}")
+ availableComponents = newComponents
+ availableServices = newServices
+ val currentServices = getCurrentServices()
+ callbacks.forEach {
+ it.onServicesUpdated(currentServices)
+ }
}
}
}
init {
+ Log.d(TAG, "Initializing")
serviceListing.addCallback(serviceListingCallback)
serviceListing.setListening(true)
serviceListing.reload()
@@ -106,9 +118,6 @@
}
}
- // All operations in background thread
- private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>()
-
/**
* Adds a callback to this controller.
*
@@ -119,9 +128,10 @@
*/
override fun addCallback(listener: ControlsListingController.ControlsListingCallback) {
backgroundExecutor.execute {
- Log.d(TAG, "Subscribing callback")
+ val services = getCurrentServices()
+ Log.d(TAG, "Subscribing callback, service count: ${services.size}")
callbacks.add(listener)
- listener.onServicesUpdated(getCurrentServices())
+ listener.onServicesUpdated(services)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
index 5c30b5a5..0d23557 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
@@ -70,6 +70,7 @@
ControlsProviderService.EXTRA_CONTROL.let {
putExtra(it, intent.getParcelableExtra<Control>(it))
}
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
}
activityIntent.putExtra(Intent.EXTRA_USER_ID, context.userId)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index 70092d3..3fab4c8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -59,9 +59,4 @@
* retain context with their favorited controls in the power menu.
*/
fun longPress(cvh: ControlViewHolder)
-
- /**
- * Event to inform the UI that the user has has focused on a single control.
- */
- fun setFocusedElement(cvh: ControlViewHolder?)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 9e6f588..9055479 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -19,6 +19,8 @@
import android.app.Dialog
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
import android.os.Vibrator
import android.os.VibrationEffect
import android.service.controls.Control
@@ -26,13 +28,12 @@
import android.service.controls.actions.CommandAction
import android.util.Log
import android.view.HapticFeedbackConstants
-import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
-
-import dagger.Lazy
+import com.android.systemui.R
import javax.inject.Inject
import javax.inject.Singleton
@@ -41,7 +42,7 @@
class ControlActionCoordinatorImpl @Inject constructor(
private val context: Context,
private val bgExecutor: DelayableExecutor,
- private val controlsController: Lazy<ControlsController>,
+ @Main private val uiExecutor: DelayableExecutor,
private val activityStarter: ActivityStarter,
private val keyguardStateController: KeyguardStateController,
private val globalActionsComponent: GlobalActionsComponent
@@ -95,10 +96,6 @@
}
}
- override fun setFocusedElement(cvh: ControlViewHolder?) {
- controlsController.get().onFocusChanged(cvh?.cws)
- }
-
private fun bouncerOrRun(f: () -> Unit) {
if (!keyguardStateController.isUnlocked()) {
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
@@ -118,9 +115,24 @@
}
private fun showDialog(cvh: ControlViewHolder, intent: Intent) {
- dialog = DetailDialog(cvh, intent).also {
- it.setOnDismissListener { _ -> dialog = null }
- it.show()
+ bgExecutor.execute {
+ val activities: List<ResolveInfo> = cvh.context.packageManager.queryIntentActivities(
+ intent,
+ PackageManager.MATCH_DEFAULT_ONLY
+ )
+
+ uiExecutor.execute {
+ // make sure the intent is valid before attempting to open the dialog
+ if (activities.isNotEmpty()) {
+ dialog = DetailDialog(cvh, intent).also {
+ it.setOnDismissListener { _ -> dialog = null }
+ it.show()
+ }
+ } else {
+ cvh.setTransientStatus(
+ cvh.context.resources.getString(R.string.controls_error_failed))
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index a9b540e..2653ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -73,8 +73,6 @@
private val toggleBackgroundIntensity: Float = layout.context.resources
.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1)
- private val dimmedAlpha: Float = layout.context.resources
- .getFraction(R.fraction.controls_dimmed_alpha, 1, 1)
private var stateAnimator: ValueAnimator? = null
private val baseLayer: GradientDrawable
val icon: ImageView = layout.requireViewById(R.id.icon)
@@ -91,11 +89,6 @@
val deviceType: Int
get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
- var dimmed: Boolean = false
- set(value) {
- field = value
- bindData(cws)
- }
init {
val ld = layout.getBackground() as LayerDrawable
@@ -222,7 +215,6 @@
val fg = context.resources.getColorStateList(ri.foreground, context.theme)
val bg = context.resources.getColor(R.color.control_default_background, context.theme)
- val dimAlpha = if (dimmed) dimmedAlpha else 1f
var (newClipColor, newAlpha) = if (enabled) {
// allow color overrides for the enabled state only
val color = cws.control?.getCustomColor()?.let {
@@ -269,7 +261,7 @@
setColor(ColorUtils.blendARGB(oldColor, newClipColor, it.animatedFraction))
baseLayer.setColor(ColorUtils.blendARGB(oldBaseColor,
newBaseColor, it.animatedFraction))
- layout.alpha = MathUtils.lerp(oldAlpha, dimAlpha, it.animatedFraction)
+ layout.alpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
@@ -284,7 +276,7 @@
alpha = newAlpha
setColor(newClipColor)
baseLayer.setColor(newBaseColor)
- layout.alpha = dimAlpha
+ layout.alpha = 1f
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index aed7cd3..4e4c82c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -31,11 +31,17 @@
fun show(parent: ViewGroup, dismissGlobalActions: Runnable)
fun hide()
+
+ /**
+ * Request all open dialogs be closed. Set [immediately] to true to dismiss without
+ * animations.
+ */
+ fun closeDialogs(immediately: Boolean)
+
fun onRefreshState(componentName: ComponentName, controls: List<Control>)
fun onActionResponse(
componentName: ComponentName,
controlId: String,
@ControlAction.ResponseResult response: Int
)
- fun onFocusChanged(controlWithState: ControlWithState?)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 7108966..52d564d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -35,7 +35,6 @@
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
-import android.view.View.MeasureSpec
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
@@ -58,6 +57,7 @@
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.globalactions.GlobalActionsPopupMenu
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -217,20 +217,6 @@
}
}
- override fun onFocusChanged(focusedControl: ControlWithState?) {
- controlViewsById.forEach { key: ControlKey, viewHolder: ControlViewHolder ->
- val state = controlsById.get(key) ?: return@forEach
- val shouldBeDimmed = focusedControl != null && state != focusedControl
- if (viewHolder.dimmed == shouldBeDimmed) {
- return@forEach
- }
-
- uiExecutor.execute {
- viewHolder.dimmed = shouldBeDimmed
- }
- }
- }
-
private fun startFavoritingActivity(context: Context, si: StructureInfo) {
startTargetedActivity(context, si, ControlsFavoritingActivity::class.java)
}
@@ -287,14 +273,6 @@
createMenu()
}
- private fun createPopup(): ListPopupWindow {
- return ListPopupWindow(
- ContextThemeWrapper(context, R.style.Control_ListPopupWindow)).apply {
- setWindowLayoutType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
- setModal(true)
- }
- }
-
private fun createMenu() {
val items = arrayOf(
context.resources.getString(R.string.controls_menu_add),
@@ -306,7 +284,7 @@
val anchor = parent.requireViewById<ImageView>(R.id.controls_more)
anchor.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
- popup = createPopup().apply {
+ popup = GlobalActionsPopupMenu(context, false /* isDropDownMode */).apply {
setAnchorView(anchor)
setAdapter(adapter)
setOnItemClickListener(object : AdapterView.OnItemClickListener {
@@ -329,20 +307,6 @@
dismiss()
}
})
- // need to call show() first in order to construct the listView
- show()
- var width = 0
- getListView()?.apply {
- // width should be between [.5, .9] of screen
- val parentWidth = this@ControlsUiControllerImpl.parent.getWidth()
- val widthSpec = MeasureSpec.makeMeasureSpec(
- (parentWidth * 0.9).toInt(), MeasureSpec.AT_MOST)
- val child = adapter.getView(0, null, this)
- child.measure(widthSpec, MeasureSpec.UNSPECIFIED)
- width = Math.max(child.getMeasuredWidth(), (parentWidth * 0.5).toInt())
- }
- setWidth(width)
- setHorizontalOffset(-width + anchor.getWidth())
show()
}
}
@@ -408,9 +372,6 @@
(getBackground() as LayerDrawable).getDrawable(1)
.setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
}
- parent.requireViewById<ImageView>(R.id.app_icon).apply {
- setImageDrawable(selectionItem.icon)
- }
if (itemsWithStructure.size == 1) {
spinner.setBackground(null)
@@ -420,9 +381,14 @@
val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
anchor.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
- popup = createPopup().apply {
+ popup = GlobalActionsPopupMenu(context, true /* isDropDownMode */).apply {
setAnchorView(anchor)
setAdapter(adapter)
+ val theme = ContextThemeWrapper(context, R.style.Control_ListPopupWindow)
+ .getTheme()
+ setBackgroundDrawable(
+ context.resources.getDrawable(R.drawable.rounded_bg_full, theme))
+
setOnItemClickListener(object : AdapterView.OnItemClickListener {
override fun onItemClick(
parent: AdapterView<*>,
@@ -435,14 +401,6 @@
dismiss()
}
})
- // need to call show() first in order to construct the listView
- show()
- getListView()?.apply {
- setDividerHeight(
- context.resources.getDimensionPixelSize(R.dimen.control_list_divider))
- setDivider(
- context.resources.getDrawable(R.drawable.controls_list_divider))
- }
show()
}
}
@@ -545,15 +503,24 @@
}
}
- override fun hide() {
- Log.d(ControlsUiController.TAG, "hide()")
- hidden = true
- popup?.dismissImmediate()
+ override fun closeDialogs(immediately: Boolean) {
+ if (immediately) {
+ popup?.dismissImmediate()
+ } else {
+ popup?.dismiss()
+ }
+ popup = null
controlViewsById.forEach {
it.value.dismiss()
}
controlActionCoordinator.closeDialogs()
+ }
+
+ override fun hide() {
+ hidden = true
+
+ closeDialogs(true)
controlsController.get().unsubscribe()
parent.removeAllViews()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 65ed967..236fa2d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -28,6 +28,7 @@
import android.view.WindowManager
import android.widget.ImageView
+import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.R
/**
@@ -41,8 +42,12 @@
) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
companion object {
- private const val ALPHA = (0.8f * 255).toInt()
private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset"
+ /*
+ * Indicate to the activity that it is being rendered in a bottomsheet, and they
+ * should optimize the layout for a smaller space.
+ */
+ private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL"
}
var activityView = ActivityView(context, null, 0, false)
@@ -50,6 +55,7 @@
val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
override fun onActivityViewReady(view: ActivityView) {
val launchIntent = Intent(intent)
+ launchIntent.putExtra(EXTRA_USE_PANEL, true)
// Apply flags to make behaviour match documentLaunchMode=always.
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -112,6 +118,12 @@
setOnClickListener { dismiss() }
(getParent() as View).setOnClickListener { dismiss() }
}
+
+ if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(context.getResources())) {
+ val cornerRadius = context.resources
+ .getDimensionPixelSize(R.dimen.controls_activity_view_corner_radius)
+ activityView.setCornerRadius(cornerRadius.toFloat())
+ }
}
override fun show() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index bfc0645..3dc0ff3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -145,6 +145,10 @@
template.isChecked())
true
}
+ AccessibilityNodeInfo.ACTION_LONG_CLICK -> {
+ cvh.controlActionCoordinator.longPress(cvh)
+ true
+ }
AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS.getId() -> {
if (arguments == null || !arguments.containsKey(
AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)) {
@@ -152,8 +156,8 @@
} else {
val value = arguments.getFloat(
AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
- val level = rangeToLevelValue(value - rangeTemplate.getCurrentValue())
- updateRange(level, template.isChecked(), /* isDragging */ false)
+ val level = rangeToLevelValue(value)
+ updateRange(level, template.isChecked(), /* isDragging */ true)
endUpdateRange()
true
}
@@ -168,27 +172,24 @@
host: ViewGroup,
child: View,
event: AccessibilityEvent
- ): Boolean = false
+ ): Boolean = true
})
}
fun beginUpdateRange() {
status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
.getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
- cvh.controlActionCoordinator.setFocusedElement(cvh)
}
fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) {
val newLevel = if (checked) Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level)) else MIN_LEVEL
- if (newLevel == clipLayer.level) return
-
rangeAnimator?.cancel()
if (isDragging) {
clipLayer.level = newLevel
val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
cvh.controlActionCoordinator.drag(isEdge)
- } else {
+ } else if (newLevel != clipLayer.level) {
rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
addUpdateListener {
cvh.clipLayer.level = it.animatedValue as Int
@@ -248,7 +249,6 @@
status.setText("$currentStatusText $currentRangeValue")
cvh.action(FloatAction(rangeTemplate.getTemplateId(),
findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
- cvh.controlActionCoordinator.setFocusedElement(null)
}
fun findNearestStep(value: Float): Float {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 3a4b273..23bcb29 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -33,6 +33,8 @@
import android.view.WindowManager;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
@@ -218,4 +220,11 @@
public Choreographer providesChoreographer() {
return Choreographer.getInstance();
}
+
+ /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
+ @Singleton
+ @Provides
+ static UiEventLogger provideUiEventLogger() {
+ return new UiEventLoggerImpl();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 8c572fe..6d1bf72 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -20,10 +20,15 @@
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
import androidx.annotation.Nullable;
import com.android.keyguard.KeyguardViewController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.plugins.qs.QSFactory;
@@ -81,10 +86,17 @@
abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager(
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
- @Binds
+ @Provides
@Singleton
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
+ static BatteryController provideBatteryController(Context context,
+ EnhancedEstimates enhancedEstimates, PowerManager powerManager,
+ BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler,
+ @Background Handler bgHandler) {
+ BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
+ broadcastDispatcher, mainHandler, bgHandler);
+ bC.init();
+ return bC;
+ }
@Binds
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java
new file mode 100644
index 0000000..e90781b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/LongRunning.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface LongRunning {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 10776c9..e1081cd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -41,6 +41,9 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -56,8 +59,8 @@
public class DozeSensors {
private static final boolean DEBUG = DozeService.DEBUG;
-
private static final String TAG = "DozeSensors";
+ private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
private final Context mContext;
private final AlarmManager mAlarmManager;
@@ -79,6 +82,23 @@
private boolean mListening;
private boolean mPaused;
+ @VisibleForTesting
+ public enum DozeSensorsUiEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "User performs pickup gesture that activates the ambient display")
+ ACTION_AMBIENT_GESTURE_PICKUP(459);
+
+ private final int mId;
+
+ DozeSensorsUiEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog) {
@@ -416,6 +436,7 @@
MetricsLogger.action(
mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
subType);
+ UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP);
}
mRegistered = false;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 8123158..cf3538c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -23,6 +23,10 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -82,7 +86,6 @@
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
-import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -2021,42 +2024,23 @@
}
private ListPopupWindow createPowerOverflowPopup() {
- ListPopupWindow popup = new ListPopupWindow(new ContextThemeWrapper(
- mContext, com.android.systemui.R.style.Control_ListPopupWindow));
- popup.setWindowLayoutType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ ListPopupWindow popup = new GlobalActionsPopupMenu(
+ mContext, false /* isDropDownMode */);
View overflowButton =
findViewById(com.android.systemui.R.id.global_actions_overflow_button);
popup.setAnchorView(overflowButton);
- int parentWidth = mGlobalActionsLayout.getWidth();
- // arbitrarily set the menu width to half of parent
- // TODO: Logic for menu sizing based on contents.
- int halfParentWidth = Math.round(parentWidth * 0.5f);
- popup.setContentWidth(halfParentWidth);
popup.setAdapter(mOverflowAdapter);
- popup.setModal(true);
return popup;
}
private void showPowerOverflowMenu() {
- mOverflowPopup.show();
-
- // Width is fixed to slightly more than half of the GlobalActionsLayout container.
- // TODO: Resize the width of this dialog based on the sizes of the items in it.
- int width = Math.round(mGlobalActionsLayout.getWidth() * 0.6f);
-
- ListView listView = mOverflowPopup.getListView();
- listView.setDividerHeight(mContext.getResources()
- .getDimensionPixelSize(com.android.systemui.R.dimen.control_list_divider));
- listView.setDivider(mContext.getResources().getDrawable(
- com.android.systemui.R.drawable.controls_list_divider));
- mOverflowPopup.setWidth(width);
- mOverflowPopup.setHorizontalOffset(-width + mOverflowPopup.getAnchorView().getWidth());
- mOverflowPopup.setVerticalOffset(mOverflowPopup.getAnchorView().getHeight());
+ mOverflowPopup = createPowerOverflowPopup();
mOverflowPopup.show();
}
private void hidePowerOverflowMenu() {
mOverflowPopup.dismiss();
+ mOverflowPopup = null;
}
private void initializeLayout() {
@@ -2081,8 +2065,6 @@
mContainer = mGlobalActionsLayout;
}
- mOverflowPopup = createPowerOverflowPopup();
-
View overflowButton = findViewById(
com.android.systemui.R.id.global_actions_overflow_button);
if (overflowButton != null) {
@@ -2196,24 +2178,7 @@
mShowing = true;
mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
mNotificationShadeWindowController.setForceHasTopUi(true);
- mBackgroundDrawable.setAlpha(0);
- mContainer.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX());
- mContainer.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY());
- mContainer.setAlpha(0);
- mContainer.animate()
- .alpha(1)
- .translationX(0)
- .translationY(0)
- .setDuration(450)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setUpdateListener(animation -> {
- float animatedValue = animation.getAnimatedFraction();
- int alpha = (int) (animatedValue * mScrimAlpha * 255);
- mBackgroundDrawable.setAlpha(alpha);
- mDepthController.updateGlobalDialogVisibility(animatedValue,
- mGlobalActionsLayout);
- })
- .start();
+
ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView();
root.setOnApplyWindowInsetsListener((v, windowInsets) -> {
if (mUseControlsLayout) {
@@ -2227,29 +2192,66 @@
if (mControlsUiController != null) {
mControlsUiController.show(mControlsView, this::dismissForControlsActivity);
}
+
+ mBackgroundDrawable.setAlpha(0);
+ float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
+ ObjectAnimator alphaAnimator =
+ ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 0f, 1f);
+ alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ alphaAnimator.setDuration(183);
+ alphaAnimator.addUpdateListener((animation) -> {
+ float animatedValue = animation.getAnimatedFraction();
+ int alpha = (int) (animatedValue * mScrimAlpha * 255);
+ mBackgroundDrawable.setAlpha(alpha);
+ mDepthController.updateGlobalDialogVisibility(animatedValue,
+ mGlobalActionsLayout);
+ });
+
+ ObjectAnimator xAnimator =
+ ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f);
+ alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ alphaAnimator.setDuration(350);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(alphaAnimator, xAnimator);
+ animatorSet.start();
}
@Override
public void dismiss() {
dismissWithAnimation(() -> {
mContainer.setTranslationX(0);
- mContainer.setTranslationY(0);
- mContainer.setAlpha(1);
- mContainer.animate()
- .alpha(0)
- .translationX(mGlobalActionsLayout.getAnimationOffsetX())
- .translationY(mGlobalActionsLayout.getAnimationOffsetY())
- .setDuration(450)
- .withEndAction(this::completeDismiss)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setUpdateListener(animation -> {
- float animatedValue = 1f - animation.getAnimatedFraction();
- int alpha = (int) (animatedValue * mScrimAlpha * 255);
- mBackgroundDrawable.setAlpha(alpha);
- mDepthController.updateGlobalDialogVisibility(animatedValue,
- mGlobalActionsLayout);
- })
- .start();
+ ObjectAnimator alphaAnimator =
+ ObjectAnimator.ofFloat(mContainer, "transitionAlpha", 1f, 0f);
+ alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ alphaAnimator.setDuration(233);
+ alphaAnimator.addUpdateListener((animation) -> {
+ float animatedValue = 1f - animation.getAnimatedFraction();
+ int alpha = (int) (animatedValue * mScrimAlpha * 255);
+ mBackgroundDrawable.setAlpha(alpha);
+ mDepthController.updateGlobalDialogVisibility(animatedValue,
+ mGlobalActionsLayout);
+ });
+
+ float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
+ ObjectAnimator xAnimator =
+ ObjectAnimator.ofFloat(mContainer, "translationX", 0f, xOffset);
+ alphaAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ alphaAnimator.setDuration(350);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(alphaAnimator, xAnimator);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ completeDismiss();
+ }
+ });
+
+ animatorSet.start();
+
+ // close first, as popup windows will not fade during the animation
+ dismissOverflow(false);
+ if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
index 2f32d97..c7612d4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
@@ -90,11 +90,11 @@
@Override
public float getAnimationOffsetX() {
- return 0;
+ return getAnimationDistance();
}
@Override
public float getAnimationOffsetY() {
- return -getAnimationDistance();
+ return 0f;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
new file mode 100644
index 0000000..02ea251
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.globalactions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.WindowManager;
+import android.widget.ListAdapter;
+import android.widget.ListPopupWindow;
+import android.widget.ListView;
+
+import com.android.systemui.R;
+
+/**
+ * Customized widget for use in the GlobalActionsDialog. Ensures common positioning and user
+ * interactions.
+ */
+public class GlobalActionsPopupMenu extends ListPopupWindow {
+ private Context mContext;
+ private boolean mIsDropDownMode;
+ private int mMenuHorizontalPadding = 0;
+ private int mMenuVerticalPadding = 0;
+ private int mGlobalActionsSidePadding = 0;
+ private ListAdapter mAdapter;
+
+ public GlobalActionsPopupMenu(@NonNull Context context, boolean isDropDownMode) {
+ super(new ContextThemeWrapper(context, R.style.Control_ListPopupWindow));
+ mContext = context;
+ mIsDropDownMode = isDropDownMode;
+
+ // required to show above the global actions dialog
+ setWindowLayoutType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ setModal(true);
+
+ Resources res = mContext.getResources();
+ mGlobalActionsSidePadding = res.getDimensionPixelSize(R.dimen.global_actions_side_margin);
+ if (!isDropDownMode) {
+ mMenuVerticalPadding = res.getDimensionPixelSize(R.dimen.control_menu_vertical_padding);
+ mMenuHorizontalPadding =
+ res.getDimensionPixelSize(R.dimen.control_menu_horizontal_padding);
+ }
+ }
+
+ /**
+ * Set the listadapter used to populate this menu.
+ */
+ public void setAdapter(@Nullable ListAdapter adapter) {
+ mAdapter = adapter;
+ super.setAdapter(adapter);
+ }
+
+ /**
+ * Show the dialog.
+ */
+ public void show() {
+ // need to call show() first in order to construct the listView
+ super.show();
+
+ ListView listView = getListView();
+ Resources res = mContext.getResources();
+
+ setVerticalOffset(-getAnchorView().getHeight() / 2);
+
+ if (mIsDropDownMode) {
+ // use a divider
+ listView.setDividerHeight(res.getDimensionPixelSize(R.dimen.control_list_divider));
+ listView.setDivider(res.getDrawable(R.drawable.controls_list_divider_inset));
+ } else {
+ if (mAdapter == null) return;
+
+ // width should be between [.5, .9] of screen
+ int parentWidth = res.getSystem().getDisplayMetrics().widthPixels;
+ int widthSpec = MeasureSpec.makeMeasureSpec(
+ (int) (parentWidth * 0.9), MeasureSpec.AT_MOST);
+ View child = mAdapter.getView(0, null, listView);
+ child.measure(widthSpec, MeasureSpec.UNSPECIFIED);
+ int width = Math.max(child.getMeasuredWidth(), (int) (parentWidth * 0.5));
+
+ listView.setPadding(mMenuHorizontalPadding, mMenuVerticalPadding,
+ mMenuHorizontalPadding, mMenuVerticalPadding);
+
+ setWidth(width);
+ setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
+ }
+
+ super.show();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
new file mode 100644
index 0000000..9374727
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
@@ -0,0 +1,264 @@
+package com.android.systemui.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.content.res.Resources
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.RadialGradient
+import android.graphics.Rect
+import android.graphics.Shader
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.util.MathUtils
+import android.util.MathUtils.lerp
+import android.view.MotionEvent
+import android.view.View
+import androidx.annotation.Keep
+import com.android.internal.graphics.ColorUtils
+import com.android.internal.graphics.ColorUtils.blendARGB
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+import org.xmlpull.v1.XmlPullParser
+
+private const val BACKGROUND_ANIM_DURATION = 370L
+private const val RIPPLE_ANIM_DURATION = 800L
+private const val RIPPLE_DOWN_PROGRESS = 0.05f
+private const val RIPPLE_CANCEL_DURATION = 200L
+private val GRADIENT_STOPS = floatArrayOf(0.2f, 1f)
+
+private data class RippleData(
+ var x: Float,
+ var y: Float,
+ var alpha: Float,
+ var progress: Float,
+ var minSize: Float,
+ var maxSize: Float,
+ var highlight: Float
+)
+
+/**
+ * Drawable that can draw an animated gradient when tapped.
+ */
+@Keep
+class IlluminationDrawable : Drawable() {
+
+ private var cornerRadius = 0f
+ private var highlightColor = Color.TRANSPARENT
+ private val rippleData = RippleData(0f, 0f, 0f, 0f, 0f, 0f, 0f)
+ private var tmpHsl = floatArrayOf(0f, 0f, 0f)
+ private var paint = Paint()
+
+ private var backgroundColor = Color.TRANSPARENT
+ set(value) {
+ if (value == field) {
+ return
+ }
+ field = value
+ animateBackground()
+ }
+
+ /**
+ * Draw a small highlight under the finger before expanding (or cancelling) it.
+ */
+ private var pressed: Boolean = false
+ set(value) {
+ if (value == field) {
+ return
+ }
+ field = value
+
+ if (value) {
+ rippleAnimation?.cancel()
+ rippleData.alpha = 1f
+ rippleData.progress = RIPPLE_DOWN_PROGRESS
+ } else {
+ rippleAnimation?.cancel()
+ rippleAnimation = ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
+ duration = RIPPLE_CANCEL_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ var cancelled = false
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true;
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ if (cancelled) {
+ return
+ }
+ rippleData.progress = 0f
+ rippleData.alpha = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ })
+ start()
+ }
+ }
+ invalidateSelf()
+ }
+
+ private var rippleAnimation: Animator? = null
+ private var backgroundAnimation: ValueAnimator? = null
+
+ /**
+ * Draw background and gradient.
+ */
+ override fun draw(canvas: Canvas) {
+ paint.shader = if (rippleData.progress > 0) {
+ val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
+ val centerColor = blendARGB(paint.color, highlightColor, rippleData.alpha)
+ RadialGradient(rippleData.x, rippleData.y, radius, intArrayOf(centerColor, paint.color),
+ GRADIENT_STOPS, Shader.TileMode.CLAMP)
+ } else {
+ null
+ }
+ canvas.drawRoundRect(0f, 0f, bounds.width().toFloat(), bounds.height().toFloat(),
+ cornerRadius, cornerRadius, paint)
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.TRANSPARENT
+ }
+
+ override fun inflate(
+ r: Resources,
+ parser: XmlPullParser,
+ attrs: AttributeSet,
+ theme: Resources.Theme?
+ ) {
+ val a = obtainAttributes(r, theme, attrs, R.styleable.IlluminationDrawable)
+ cornerRadius = a.getDimension(R.styleable.IlluminationDrawable_cornerRadius, cornerRadius)
+ rippleData.minSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMinSize, 0f)
+ rippleData.maxSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMaxSize, 0f)
+ rippleData.highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) / 100f
+ a.recycle()
+ }
+
+ override fun setColorFilter(p0: ColorFilter?) {
+ throw UnsupportedOperationException("Color filters are not supported")
+ }
+
+ override fun setAlpha(value: Int) {
+ throw UnsupportedOperationException("Alpha is not supported")
+ }
+
+ /**
+ * Cross fade background.
+ * @see setTintList
+ * @see backgroundColor
+ */
+ private fun animateBackground() {
+ ColorUtils.colorToHSL(backgroundColor, tmpHsl)
+ val L = tmpHsl[2]
+ tmpHsl[2] = MathUtils.constrain(if (L < 1f - rippleData.highlight) {
+ L + rippleData.highlight
+ } else {
+ L - rippleData.highlight
+ }, 0f, 1f)
+
+ val initialBackground = paint.color
+ val initialHighlight = highlightColor
+ val finalHighlight = ColorUtils.HSLToColor(tmpHsl)
+
+ backgroundAnimation?.cancel()
+ backgroundAnimation = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = BACKGROUND_ANIM_DURATION
+ interpolator = Interpolators.FAST_OUT_LINEAR_IN
+ addUpdateListener {
+ val progress = it.animatedValue as Float
+ paint.color = blendARGB(initialBackground, backgroundColor, progress)
+ highlightColor = blendARGB(initialHighlight, finalHighlight, progress)
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ backgroundAnimation = null
+ }
+ })
+ start()
+ }
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ super.setTintList(tint)
+ backgroundColor = tint!!.defaultColor
+ }
+
+ /**
+ * Draws an animated ripple that expands fading away.
+ */
+ private fun illuminate() {
+ rippleData.alpha = 1f
+ invalidateSelf()
+
+ rippleAnimation?.cancel()
+ rippleAnimation = AnimatorSet().apply {
+ playTogether(ValueAnimator.ofFloat(1f, 0f).apply {
+ startDelay = 133
+ duration = RIPPLE_ANIM_DURATION - startDelay
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
+ invalidateSelf()
+ }
+ }, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
+ duration = RIPPLE_ANIM_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.progress = it.animatedValue as Float
+ invalidateSelf()
+ }
+ })
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ rippleData.progress = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ })
+ start()
+ }
+ }
+
+ /**
+ * Setup touch events on a view such as tapping it would trigger effects on this drawable.
+ * @param target View receiving touched.
+ * @param container View that holds this drawable.
+ */
+ fun setupTouch(target: View, container: View) {
+ val containerRect = Rect()
+ target.setOnTouchListener { view: View, event: MotionEvent ->
+ container.getGlobalVisibleRect(containerRect)
+ rippleData.x = event.rawX - containerRect.left
+ rippleData.y = event.rawY - containerRect.top
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ pressed = true
+ }
+ MotionEvent.ACTION_MOVE -> {
+ invalidateSelf()
+ }
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ pressed = false
+ if (event.action == MotionEvent.ACTION_UP) {
+ illuminate()
+ }
+ }
+ }
+ false
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 9509e6d..557132b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -98,6 +98,7 @@
private SharedPreferences mSharedPrefs;
private boolean mCheckedForResumption = false;
private boolean mIsRemotePlayback;
+ private QSMediaBrowser mQSMediaBrowser;
// Button IDs used in notifications
protected static final int[] NOTIF_ACTION_IDS = {
@@ -232,6 +233,11 @@
String key) {
// Ensure that component names are updated if token has changed
if (mToken == null || !mToken.equals(token)) {
+ if (mQSMediaBrowser != null) {
+ Log.d(TAG, "Disconnecting old media browser");
+ mQSMediaBrowser.disconnect();
+ mQSMediaBrowser = null;
+ }
mToken = token;
mServiceComponent = null;
mCheckedForResumption = false;
@@ -315,11 +321,8 @@
appName.setTextColor(mForegroundColor);
}
+ // Can be null!
MediaMetadata mediaMetadata = mController.getMetadata();
- if (mediaMetadata == null) {
- Log.e(TAG, "Media metadata was null");
- return;
- }
ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
if (albumView != null) {
@@ -329,14 +332,20 @@
// Song name
TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
- String songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ String songName = "";
+ if (mediaMetadata != null) {
+ songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ }
titleText.setText(songName);
titleText.setTextColor(mForegroundColor);
// Artist name (not in mini player)
TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
if (artistText != null) {
- String artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ String artistName = "";
+ if (mediaMetadata != null) {
+ artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ }
artistText.setText(artistName);
artistText.setTextColor(mForegroundColor);
}
@@ -439,21 +448,23 @@
private void processAlbumArt(MediaMetadata metadata, Icon largeIcon, ImageView albumView) {
Bitmap albumArt = null;
- // First look in URI fields
- for (String field : ART_URIS) {
- String uriString = metadata.getString(field);
- if (!TextUtils.isEmpty(uriString)) {
- albumArt = loadBitmapFromUri(Uri.parse(uriString));
- if (albumArt != null) {
- Log.d(TAG, "loaded art from " + field);
- break;
+ if (metadata != null) {
+ // First look in URI fields
+ for (String field : ART_URIS) {
+ String uriString = metadata.getString(field);
+ if (!TextUtils.isEmpty(uriString)) {
+ albumArt = loadBitmapFromUri(Uri.parse(uriString));
+ if (albumArt != null) {
+ Log.d(TAG, "loaded art from " + field);
+ break;
+ }
}
}
- }
- // Then check bitmap field
- if (albumArt == null) {
- albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ // Then check bitmap field
+ if (albumArt == null) {
+ albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ }
}
// Finally try the notification's largeIcon
@@ -613,8 +624,22 @@
ImageButton btn = mMediaNotifView.findViewById(mActionIds[0]);
btn.setOnClickListener(v -> {
Log.d(TAG, "Attempting to restart session");
- QSMediaBrowser browser = new QSMediaBrowser(mContext, null, mServiceComponent);
- browser.restart();
+ if (mQSMediaBrowser != null) {
+ mQSMediaBrowser.disconnect();
+ }
+ mQSMediaBrowser = new QSMediaBrowser(mContext, new QSMediaBrowser.Callback(){
+ @Override
+ public void onConnected() {
+ Log.d(TAG, "Successfully restarted");
+ }
+ @Override
+ public void onError() {
+ Log.e(TAG, "Error restarting");
+ mQSMediaBrowser.disconnect();
+ mQSMediaBrowser = null;
+ }
+ }, mServiceComponent);
+ mQSMediaBrowser.restart();
});
btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
@@ -649,13 +674,18 @@
*/
private void tryUpdateResumptionList(ComponentName componentName) {
Log.d(TAG, "Testing if we can connect to " + componentName);
- QSMediaBrowser.testConnection(mContext,
+ if (mQSMediaBrowser != null) {
+ mQSMediaBrowser.disconnect();
+ }
+ mQSMediaBrowser = new QSMediaBrowser(mContext,
new QSMediaBrowser.Callback() {
@Override
public void onConnected() {
Log.d(TAG, "yes we can resume with " + componentName);
mServiceComponent = componentName;
updateResumptionList(componentName);
+ mQSMediaBrowser.disconnect();
+ mQSMediaBrowser = null;
}
@Override
@@ -666,9 +696,12 @@
// If it's not active and we can't resume, remove
removePlayer();
}
+ mQSMediaBrowser.disconnect();
+ mQSMediaBrowser = null;
}
},
componentName);
+ mQSMediaBrowser.testConnection();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 1425100..f72a74b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -19,6 +19,7 @@
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.PlaybackState
+import android.os.SystemClock
import android.view.MotionEvent
import android.view.View
import android.widget.SeekBar
@@ -31,6 +32,38 @@
private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
+private fun PlaybackState.isInMotion(): Boolean {
+ return this.state == PlaybackState.STATE_PLAYING ||
+ this.state == PlaybackState.STATE_FAST_FORWARDING ||
+ this.state == PlaybackState.STATE_REWINDING
+}
+
+/**
+ * Gets the playback position while accounting for the time since the [PlaybackState] was last
+ * retrieved.
+ *
+ * This method closely follows the implementation of
+ * [MediaSessionRecord#getStateWithUpdatedPosition].
+ */
+private fun PlaybackState.computePosition(duration: Long): Long {
+ var currentPosition = this.position
+ if (this.isInMotion()) {
+ val updateTime = this.getLastPositionUpdateTime()
+ val currentTime = SystemClock.elapsedRealtime()
+ if (updateTime > 0) {
+ var position = (this.playbackSpeed * (currentTime - updateTime)).toLong() +
+ this.getPosition()
+ if (duration >= 0 && position > duration) {
+ position = duration.toLong()
+ } else if (position < 0) {
+ position = 0
+ }
+ currentPosition = position
+ }
+ }
+ return currentPosition
+}
+
/** ViewModel for seek bar in QS media player. */
class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
@@ -98,7 +131,8 @@
@AnyThread
private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({
- val currentPosition = controller?.playbackState?.position?.toInt()
+ val duration = _data?.duration ?: -1
+ val currentPosition = playbackState?.computePosition(duration.toLong())?.toInt()
if (currentPosition != null && _data.elapsedTime != currentPosition) {
_data = _data.copy(elapsedTime = currentPosition)
}
@@ -109,13 +143,7 @@
@WorkerThread
private fun shouldPollPlaybackPosition(): Boolean {
- val state = playbackState?.state
- val moving = if (state == null) false else
- state == PlaybackState.STATE_PLAYING ||
- state == PlaybackState.STATE_BUFFERING ||
- state == PlaybackState.STATE_FAST_FORWARDING ||
- state == PlaybackState.STATE_REWINDING
- return moving && listening
+ return listening && playbackState?.isInMotion() ?: false
}
/** Gets a listener to attach to the seek bar to handle seeking. */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index f322489..f72de11 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -376,7 +376,8 @@
// NOTE: intentionally does not apply the transaction here.
// this end transaction should get executed synchronously with the final
// WindowContainerTransaction in task organizer
- getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds());
+ getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
+ .crop(tx, leash, getDestinationBounds());
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 9d9e74a..3eeadc3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -43,11 +43,13 @@
import java.io.PrintWriter;
import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
* state changes originated from Window Manager and is the source of truth for PiP window bounds.
*/
+@Singleton
public class PipBoundsHandler {
private static final String TAG = PipBoundsHandler.class.getSimpleName();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index d38c481..8d6ce47 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -58,6 +58,9 @@
import java.util.Objects;
import java.util.function.Consumer;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Manages PiP tasks such as resize and offset.
*
@@ -69,6 +72,7 @@
* This class is also responsible for general resize/offset PiP operations within SysUI component,
* see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
*/
+@Singleton
public class PipTaskOrganizer extends TaskOrganizer {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
@@ -190,7 +194,9 @@
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private PictureInPictureParams mPictureInPictureParams;
+ @Inject
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@Nullable Divider divider) {
@@ -213,6 +219,10 @@
return new Rect(mLastReportedBounds);
}
+ public boolean isInPip() {
+ return mInPip;
+ }
+
/**
* Registers {@link PipTransitionCallback} to receive transition callbacks.
*/
@@ -238,6 +248,11 @@
* @param animationDurationMs duration in millisecond for the exiting PiP transition
*/
public void dismissPip(int animationDurationMs) {
+ if (!mInPip || mToken == null) {
+ Log.wtf(TAG, "Not allowed to dismissPip in current state"
+ + " mInPip=" + mInPip + " mToken=" + mToken);
+ return;
+ }
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
WindowOrganizer.applyTransaction(wct);
@@ -252,8 +267,9 @@
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
Objects.requireNonNull(info, "Requires RunningTaskInfo");
+ mPictureInPictureParams = info.pictureInPictureParams;
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- info.topActivity, getAspectRatioOrDefault(info.pictureInPictureParams),
+ info.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
null /* bounds */, getMinimalSize(info.topActivityInfo));
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
mTaskInfo = info;
@@ -299,6 +315,7 @@
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
+ mPictureInPictureParams = null;
mInPip = false;
}
@@ -306,7 +323,7 @@
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
final PictureInPictureParams newParams = info.pictureInPictureParams;
- if (!shouldUpdateDestinationBounds(newParams)) {
+ if (!applyPictureInPictureParams(newParams)) {
Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
return;
}
@@ -354,7 +371,7 @@
}
final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(
- mTaskInfo.topActivity, getAspectRatioOrDefault(mTaskInfo.pictureInPictureParams),
+ mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
if (newDestinationBounds.equals(currentDestinationBounds)) return;
if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
@@ -368,12 +385,14 @@
* @return {@code true} if the aspect ratio is changed since no other parameters within
* {@link PictureInPictureParams} would affect the bounds.
*/
- private boolean shouldUpdateDestinationBounds(PictureInPictureParams params) {
- if (params == null || mTaskInfo.pictureInPictureParams == null) {
- return params != mTaskInfo.pictureInPictureParams;
+ private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
+ final boolean changed = (mPictureInPictureParams == null) ? true : !Objects.equals(
+ mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
+ if (changed) {
+ mPictureInPictureParams = params;
+ mPipBoundsHandler.onAspectRatioChanged(params.getAspectRatio());
}
- return !Objects.equals(mTaskInfo.pictureInPictureParams.getAspectRatioRational(),
- params.getAspectRatioRational());
+ return changed;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index a86a884..0841bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -200,6 +200,7 @@
DeviceConfigProxy deviceConfig,
PipBoundsHandler pipBoundsHandler,
PipSnapAlgorithm pipSnapAlgorithm,
+ PipTaskOrganizer pipTaskOrganizer,
PipSurfaceTransactionHelper surfaceTransactionHelper,
Divider divider) {
mContext = context;
@@ -215,8 +216,7 @@
final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
mPipBoundsHandler = pipBoundsHandler;
- mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler,
- surfaceTransactionHelper, divider);
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 00f693d..b1e4d67 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -168,7 +168,10 @@
void synchronizePinnedStackBounds() {
cancelAnimations();
mBounds.set(mPipTaskOrganizer.getLastReportedBounds());
- mFloatingContentCoordinator.onContentMoved(this);
+
+ if (mPipTaskOrganizer.isInPip()) {
+ mFloatingContentCoordinator.onContentMoved(this);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index fae8af4..f49732d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -233,6 +233,7 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
PipBoundsHandler pipBoundsHandler,
+ PipTaskOrganizer pipTaskOrganizer,
PipSurfaceTransactionHelper surfaceTransactionHelper,
Divider divider) {
if (mInitialized) {
@@ -250,8 +251,7 @@
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- surfaceTransactionHelper, divider);
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
index 448531a..c5ae3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
@@ -20,10 +20,14 @@
import android.content.res.Configuration
import android.view.View
import android.view.ViewGroup
+import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.qs.TileLayout.exactly
-class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTileLayout {
+class DoubleLineTileLayout(
+ context: Context,
+ private val uiEventLogger: UiEventLogger
+) : ViewGroup(context), QSPanel.QSTileLayout {
companion object {
private const val NUM_LINES = 2
@@ -86,6 +90,13 @@
for (record in mRecords) {
record.tile.setListening(this, listening)
}
+ if (listening) {
+ for (i in 0 until numVisibleTiles) {
+ val tile = mRecords[i].tile
+ uiEventLogger.logWithInstanceId(
+ QSEvent.QQS_TILE_VISIBLE, 0, tile.metricsSpec, tile.instanceId)
+ }
+ }
}
override fun getNumVisibleTiles() = tilesToShow
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index cd73721..b157f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -22,7 +22,9 @@
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
@@ -63,7 +65,7 @@
private int mLayoutDirection;
private int mHorizontalClipBound;
private final Rect mClippingRect;
- private int mLastMaxHeight = -1;
+ private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -75,6 +77,7 @@
mLayoutDirection = getLayoutDirection();
mClippingRect = new Rect();
}
+ private int mLastMaxHeight = -1;
public void saveInstanceState(Bundle outState) {
outState.putInt(CURRENT_PAGE, getCurrentItem());
@@ -126,6 +129,15 @@
return page;
}
+ // This will dump to the ui log all the tiles that are visible in this page
+ private void logVisibleTiles(TilePage page) {
+ for (int i = 0; i < page.mRecords.size(); i++) {
+ QSTile t = page.mRecords.get(i).tile;
+ mUiEventLogger.logWithInstanceId(QSEvent.QS_TILE_VISIBLE, 0, t.getMetricsSpec(),
+ t.getInstanceId());
+ }
+ }
+
@Override
public void setListening(boolean listening) {
if (mListening == listening) return;
@@ -218,7 +230,11 @@
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
int currentItem = getCurrentPageNumber();
for (int i = 0; i < mPages.size(); i++) {
- mPages.get(i).setSelected(i == currentItem ? selected : false);
+ TilePage page = mPages.get(i);
+ page.setSelected(i == currentItem ? selected : false);
+ if (page.isSelected()) {
+ logVisibleTiles(page);
+ }
}
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
@@ -419,6 +435,7 @@
mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
: position == 0);
}
+
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 17aaff1..ee3b499 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -39,6 +39,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -53,6 +54,7 @@
private static final long FADE_DURATION = 300;
private final SparseArray<View> mDetailViews = new SparseArray<>();
+ private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
private ViewGroup mDetailContent;
protected TextView mDetailSettingsButton;
@@ -205,6 +207,7 @@
mDetailContent.addView(detailView);
mDetailViews.put(viewCacheIndex, detailView);
Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory());
+ mUiEventLogger.log(adapter.openDetailEvent());
announceForAccessibility(mContext.getString(
R.string.accessibility_quick_settings_detail,
adapter.getTitle()));
@@ -214,6 +217,7 @@
} else {
if (mDetailAdapter != null) {
Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory());
+ mUiEventLogger.log(mDetailAdapter.closeDetailEvent());
}
mClosingDetail = true;
mDetailAdapter = null;
@@ -249,6 +253,7 @@
mDetailSettingsButton.setOnClickListener(v -> {
Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS,
adapter.getMetricsCategory());
+ mUiEventLogger.log(adapter.moreSettingsEvent());
Dependency.get(ActivityStarter.class)
.postStartActivityDismissingKeyguard(settingsIntent, 0);
});
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
new file mode 100644
index 0000000..54e8a2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.UiEventLoggerImpl
+import com.android.internal.logging.testing.UiEventLoggerFake
+
+object QSEvents {
+
+ var qsUiEventsLogger: UiEventLogger = UiEventLoggerImpl()
+ private set
+
+ fun setLoggerForTesting(): UiEventLoggerFake {
+ return UiEventLoggerFake().also {
+ qsUiEventsLogger = it
+ }
+ }
+
+ fun resetLogger() {
+ qsUiEventsLogger = UiEventLoggerImpl()
+ }
+}
+
+enum class QSEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Tile clicked. It has an instance id and a spec (or packageName)")
+ QS_ACTION_CLICK(387),
+
+ @UiEvent(doc = "Tile secondary button clicked. " +
+ "It has an instance id and a spec (or packageName)")
+ QS_ACTION_SECONDARY_CLICK(388),
+
+ @UiEvent(doc = "Tile long clicked. It has an instance id and a spec (or packageName)")
+ QS_ACTION_LONG_PRESS(389),
+
+ @UiEvent(doc = "Quick Settings panel expanded")
+ QS_PANEL_EXPANDED(390),
+
+ @UiEvent(doc = "Quick Settings panel collapsed")
+ QS_PANEL_COLLAPSED(391),
+
+ @UiEvent(doc = "Tile visible in Quick Settings panel. The tile may be in a different page. " +
+ "It has an instance id and a spec (or packageName)")
+ QS_TILE_VISIBLE(392),
+
+ @UiEvent(doc = "Quick Quick Settings panel expanded")
+ QQS_PANEL_EXPANDED(393),
+
+ @UiEvent(doc = "Quick Quick Settings panel collapsed")
+ QQS_PANEL_COLLAPSED(394),
+
+ @UiEvent(doc = "Tile visible in Quick Quick Settings panel. " +
+ "It has an instance id and a spec (or packageName)")
+ QQS_TILE_VISIBLE(395);
+
+ override fun getId() = _id
+}
+
+enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
+
+ @UiEvent(doc = "Tile removed from current tiles")
+ QS_EDIT_REMOVE(210),
+
+ @UiEvent(doc = "Tile added to current tiles")
+ QS_EDIT_ADD(211),
+
+ @UiEvent(doc = "Tile moved")
+ QS_EDIT_MOVE(212),
+
+ @UiEvent(doc = "QS customizer open")
+ QS_EDIT_OPEN(213),
+
+ @UiEvent(doc = "QS customizer closed")
+ QS_EDIT_CLOSED(214),
+
+ @UiEvent(doc = "QS tiles reset")
+ QS_EDIT_RESET(215);
+
+ override fun getId() = _id
+}
+
+enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "TODO(beverlyt)")
+ QS_DND_CONDITION_SELECT(420),
+
+ @UiEvent(doc = "TODO(beverlyt)")
+ QS_DND_TIME_UP(422),
+
+ @UiEvent(doc = "TODO(beverlyt)")
+ QS_DND_TIME_DOWN(423);
+
+ override fun getId() = _id
+}
+
+enum class QSUserSwitcherEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The current user has been switched in the detail panel")
+ QS_USER_SWITCH(424),
+
+ @UiEvent(doc = "User switcher QS detail panel open")
+ QS_USER_DETAIL_OPEN(425),
+
+ @UiEvent(doc = "User switcher QS detail panel closed")
+ QS_USER_DETAIL_CLOSE(426),
+
+ @UiEvent(doc = "User switcher QS detail panel more settings pressed")
+ QS_USER_MORE_SETTINGS(427);
+
+ override fun getId() = _id
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index ece1ce8b..1e8c4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -16,6 +16,8 @@
import android.content.Context;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.logging.QSLogger;
@@ -30,6 +32,7 @@
Context getContext();
Context getUserContext();
QSLogger getQSLogger();
+ UiEventLogger getUiEventLogger();
Collection<QSTile> getTiles();
void addCallback(Callback callback);
void removeCallback(Callback callback);
@@ -39,6 +42,8 @@
int indexOf(String tileSpec);
+ InstanceId getNewInstanceId();
+
interface Callback {
void onTilesChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java
index 9e53286..a5b73dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java
@@ -58,21 +58,25 @@
mContext = context;
mCallback = callback;
mComponentName = componentName;
+ }
+ /**
+ * Connects to the MediaBrowserService and looks for valid media. If a media item is returned
+ * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription.
+ * QSMediaBrowser.Callback#onConnected and QSMediaBrowser.Callback#onError will also be called
+ * when the initial connection is successful, or an error occurs. Note that it is possible for
+ * the service to connect but for no playable tracks to be found later.
+ * QSMediaBrowser#disconnect will be called automatically with this function.
+ */
+ public void findRecentMedia() {
+ Log.d(TAG, "Connecting to " + mComponentName);
+ disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
mMediaBrowser = new MediaBrowser(mContext,
mComponentName,
mConnectionCallback,
rootHints);
- }
-
- /**
- * Connects to the MediaBrowserService and looks for valid media. If a media item is returned
- * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription
- */
- public void findRecentMedia() {
- Log.d(TAG, "Connecting to " + mComponentName);
mMediaBrowser.connect();
}
@@ -94,20 +98,22 @@
} else {
Log.e(TAG, "Child found but not playable for " + mComponentName);
}
- mMediaBrowser.disconnect();
+ disconnect();
}
@Override
public void onError(String parentId) {
Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
- mMediaBrowser.disconnect();
+ mCallback.onError();
+ disconnect();
}
@Override
public void onError(String parentId, Bundle options) {
Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ ", options: " + options);
- mMediaBrowser.disconnect();
+ mCallback.onError();
+ disconnect();
}
};
@@ -134,6 +140,8 @@
@Override
public void onConnectionSuspended() {
Log.d(TAG, "Connection suspended for " + mComponentName);
+ mCallback.onError();
+ disconnect();
}
/**
@@ -143,16 +151,28 @@
public void onConnectionFailed() {
Log.e(TAG, "Connection failed for " + mComponentName);
mCallback.onError();
+ disconnect();
}
};
/**
- * Connects to the MediaBrowserService and starts playback
+ * Disconnect the media browser. This should be called after restart or testConnection have
+ * completed to close the connection.
*/
- public void restart() {
- if (mMediaBrowser.isConnected()) {
+ public void disconnect() {
+ if (mMediaBrowser != null) {
mMediaBrowser.disconnect();
}
+ mMediaBrowser = null;
+ }
+
+ /**
+ * Connects to the MediaBrowserService and starts playback. QSMediaBrowser.Callback#onError or
+ * QSMediaBrowser.Callback#onConnected will be called depending on whether it was successful.
+ * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ */
+ public void restart() {
+ disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
mMediaBrowser = new MediaBrowser(mContext, mComponentName,
@@ -165,6 +185,17 @@
controller.getTransportControls();
controller.getTransportControls().prepare();
controller.getTransportControls().play();
+ mCallback.onConnected();
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ mCallback.onError();
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ mCallback.onError();
}
}, rootHints);
mMediaBrowser.connect();
@@ -192,42 +223,44 @@
}
/**
- * Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser
- * @param mContext the context
- * @param callback methods onConnected or onError will be called to indicate whether the
- * connection was successful or not
- * @param mComponentName Component name of the MediaBrowserService this browser will connect to
+ * Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser.
+ * QSMediaBrowser.Callback#onError or QSMediaBrowser.Callback#onConnected will be called
+ * depending on whether it was successful.
+ * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
- public static MediaBrowser testConnection(Context mContext, Callback callback,
- ComponentName mComponentName) {
- final MediaBrowser.ConnectionCallback mConnectionCallback =
+ public void testConnection() {
+ disconnect();
+ final MediaBrowser.ConnectionCallback connectionCallback =
new MediaBrowser.ConnectionCallback() {
@Override
public void onConnected() {
Log.d(TAG, "connected");
- callback.onConnected();
+ if (mMediaBrowser.getRoot() == null) {
+ mCallback.onError();
+ } else {
+ mCallback.onConnected();
+ }
}
@Override
public void onConnectionSuspended() {
Log.d(TAG, "suspended");
- callback.onError();
+ mCallback.onError();
}
@Override
public void onConnectionFailed() {
Log.d(TAG, "failed");
- callback.onError();
+ mCallback.onError();
}
};
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
- MediaBrowser browser = new MediaBrowser(mContext,
+ mMediaBrowser = new MediaBrowser(mContext,
mComponentName,
- mConnectionCallback,
+ connectionCallback,
rootHints);
- browser.connect();
- return browser;
+ mMediaBrowser.connect();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index e76cd51..174441b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
@@ -38,6 +39,7 @@
import com.android.settingslib.media.LocalMediaManager;
import com.android.systemui.R;
+import com.android.systemui.media.IlluminationDrawable;
import com.android.systemui.media.MediaControlPanel;
import com.android.systemui.media.SeekBarObserver;
import com.android.systemui.media.SeekBarViewModel;
@@ -173,7 +175,7 @@
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
int i = 0;
for (; i < parentActionsLayout.getChildCount() && i < QS_ACTION_IDS.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
+ final ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
ImageButton thatBtn = parentActionsLayout.findViewById(NOTIF_ACTION_IDS[i]);
if (thatBtn == null || thatBtn.getDrawable() == null
|| thatBtn.getVisibility() != View.VISIBLE) {
@@ -181,6 +183,11 @@
continue;
}
+ if (mMediaNotifView.getBackground() instanceof IlluminationDrawable) {
+ ((IlluminationDrawable) mMediaNotifView.getBackground())
+ .setupTouch(thisBtn, mMediaNotifView);
+ }
+
Drawable thatIcon = thatBtn.getDrawable();
thisBtn.setImageDrawable(thatIcon.mutate());
thisBtn.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 121e2aa..e8f6c96 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -52,6 +52,7 @@
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.settingslib.Utils;
@@ -129,6 +130,7 @@
private BrightnessController mBrightnessController;
private final DumpManager mDumpManager;
private final QSLogger mQSLogger;
+ protected final UiEventLogger mUiEventLogger;
protected QSTileHost mHost;
protected QSSecurityFooter mFooter;
@@ -176,7 +178,8 @@
@Background DelayableExecutor backgroundExecutor,
@Nullable LocalBluetoothManager localBluetoothManager,
ActivityStarter activityStarter,
- NotificationEntryManager entryManager
+ NotificationEntryManager entryManager,
+ UiEventLogger uiEventLogger
) {
super(context, attrs);
mContext = context;
@@ -188,6 +191,7 @@
mBroadcastDispatcher = broadcastDispatcher;
mActivityStarter = activityStarter;
mNotificationEntryManager = entryManager;
+ mUiEventLogger = uiEventLogger;
setOrientation(VERTICAL);
@@ -266,27 +270,8 @@
return;
}
- QSMediaPlayer player = null;
String packageName = notif.getPackageName();
- for (QSMediaPlayer p : mMediaPlayers) {
- if (p.getKey() == null) {
- // No notification key = loaded via mediabrowser, so just match on package
- if (packageName.equals(p.getMediaPlayerPackage())) {
- Log.d(TAG, "Found matching resume player by package: " + packageName);
- player = p;
- break;
- }
- } else if (p.getMediaSessionToken().equals(token)) {
- Log.d(TAG, "Found matching player by token " + packageName);
- player = p;
- break;
- } else if (packageName.equals(p.getMediaPlayerPackage()) && key.equals(p.getKey())) {
- // Also match if it's the same package and notification key
- Log.d(TAG, "Found matching player by package " + packageName + ", " + key);
- player = p;
- break;
- }
- }
+ QSMediaPlayer player = findMediaPlayer(packageName, token, key);
int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width);
int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
@@ -295,7 +280,7 @@
lp.setMarginEnd(padding);
if (player == null) {
- Log.d(TAG, "creating new player");
+ Log.d(TAG, "creating new player for " + packageName);
// Set up listener for device changes
// TODO: integrate with MediaTransferManager?
InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(),
@@ -327,6 +312,35 @@
}
}
+ /**
+ * Check for an existing media player using the given information
+ * @param packageName
+ * @param token
+ * @param key
+ * @return a player, or null if no match found
+ */
+ private QSMediaPlayer findMediaPlayer(String packageName, MediaSession.Token token,
+ String key) {
+ for (QSMediaPlayer player : mMediaPlayers) {
+ if (player.getKey() == null || key == null) {
+ // No notification key = loaded via mediabrowser, so just match on package
+ if (packageName.equals(player.getMediaPlayerPackage())) {
+ Log.d(TAG, "Found matching resume player by package: " + packageName);
+ return player;
+ }
+ } else if (player.getMediaSessionToken().equals(token)) {
+ Log.d(TAG, "Found matching player by token " + packageName);
+ return player;
+ } else if (packageName.equals(player.getMediaPlayerPackage())
+ && key.equals(player.getKey())) {
+ // Also match if it's the same package and notification key
+ Log.d(TAG, "Found matching player by package " + packageName + ", " + key);
+ return player;
+ }
+ }
+ return null;
+ }
+
protected View getMediaPanel() {
return mMediaCarousel;
}
@@ -365,26 +379,30 @@
}
Log.d(TAG, "adding track from browser: " + desc + ", " + component);
- QSMediaPlayer player = new QSMediaPlayer(mContext, QSPanel.this,
- null, mForegroundExecutor, mBackgroundExecutor, mActivityStarter);
+ // Check if there's an old player for this app
String pkgName = component.getPackageName();
+ MediaSession.Token token = browser.getToken();
+ QSMediaPlayer player = findMediaPlayer(pkgName, token, null);
- // Add controls to carousel
- int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width);
- int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(playerWidth,
- LayoutParams.MATCH_PARENT);
- lp.setMarginStart(padding);
- lp.setMarginEnd(padding);
- mMediaCarousel.addView(player.getView(), lp);
- ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
- mMediaPlayers.add(player);
+ if (player == null) {
+ player = new QSMediaPlayer(mContext, QSPanel.this,
+ null, mForegroundExecutor, mBackgroundExecutor, mActivityStarter);
+
+ // Add to carousel
+ int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width);
+ int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(playerWidth,
+ LayoutParams.MATCH_PARENT);
+ lp.setMarginStart(padding);
+ lp.setMarginEnd(padding);
+ mMediaCarousel.addView(player.getView(), lp);
+ ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
+ mMediaPlayers.add(player);
+ }
int iconColor = Color.DKGRAY;
int bgColor = Color.LTGRAY;
-
- MediaSession.Token token = browser.getToken();
player.setMediaSession(token, desc, iconColor, bgColor, browser.getAppIntent(),
pkgName);
}
@@ -678,8 +696,10 @@
}
mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded);
if (!mExpanded) {
+ mUiEventLogger.log(closePanelEvent());
closeDetail();
} else {
+ mUiEventLogger.log(openPanelEvent());
logTiles();
}
}
@@ -786,6 +806,18 @@
return mHost.createTileView(tile, collapsedView);
}
+ protected QSEvent openPanelEvent() {
+ return QSEvent.QS_PANEL_EXPANDED;
+ }
+
+ protected QSEvent closePanelEvent() {
+ return QSEvent.QS_PANEL_COLLAPSED;
+ }
+
+ protected QSEvent tileVisibleEvent() {
+ return QSEvent.QS_TILE_VISIBLE;
+ }
+
protected boolean shouldShowDetail() {
return mExpanded;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 9e8eb3a..54a928d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -31,6 +31,9 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -73,6 +76,7 @@
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final int MAX_QS_INSTANCE_ID = 1 << 20;
public static final String TILES_SETTING = Secure.QS_TILES;
@@ -85,6 +89,8 @@
private final DumpManager mDumpManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final QSLogger mQSLogger;
+ private final UiEventLogger mUiEventLogger;
+ private final InstanceIdSequence mInstanceIdSequence;
private final List<Callback> mCallbacks = new ArrayList<>();
private AutoTileManager mAutoTiles;
@@ -106,7 +112,8 @@
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
Optional<StatusBar> statusBarOptional,
- QSLogger qsLogger) {
+ QSLogger qsLogger,
+ UiEventLogger uiEventLogger) {
mIconController = iconController;
mContext = context;
mUserContext = context;
@@ -114,8 +121,10 @@
mPluginManager = pluginManager;
mDumpManager = dumpManager;
mQSLogger = qsLogger;
+ mUiEventLogger = uiEventLogger;
mBroadcastDispatcher = broadcastDispatcher;
+ mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
mServices = new TileServices(this, bgLooper, mBroadcastDispatcher);
mStatusBarOptional = statusBarOptional;
@@ -137,6 +146,11 @@
return mIconController;
}
+ @Override
+ public InstanceId getNewInstanceId() {
+ return mInstanceIdSequence.newInstanceId();
+ }
+
public void destroy() {
mTiles.values().forEach(tile -> tile.destroy());
mAutoTiles.destroy();
@@ -170,6 +184,11 @@
}
@Override
+ public UiEventLogger getUiEventLogger() {
+ return mUiEventLogger;
+ }
+
+ @Override
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -435,11 +454,8 @@
final Resources res = context.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
- final String extraTileList = res.getString(
- com.android.internal.R.string.config_defaultExtraQuickSettingsTiles);
tiles.addAll(Arrays.asList(defaultTileList.split(",")));
- tiles.addAll(Arrays.asList(extraTileList.split(",")));
if (Build.IS_DEBUGGABLE
&& GarbageMonitor.MemoryTile.ADD_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index f77ff8c..5cb75e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -28,6 +28,7 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
+import com.android.systemui.media.IlluminationDrawable;
import com.android.systemui.media.MediaControlPanel;
import com.android.systemui.plugins.ActivityStarter;
@@ -104,6 +105,11 @@
continue;
}
+ if (mMediaNotifView.getBackground() instanceof IlluminationDrawable) {
+ ((IlluminationDrawable) mMediaNotifView.getBackground())
+ .setupTouch(thisBtn, mMediaNotifView);
+ }
+
Drawable thatIcon = thatBtn.getDrawable();
thisBtn.setImageDrawable(thatIcon.mutate());
thisBtn.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 38dea65..6683a1c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -27,6 +27,7 @@
import android.view.View;
import android.widget.LinearLayout;
+import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -88,11 +89,12 @@
@Background DelayableExecutor backgroundExecutor,
@Nullable LocalBluetoothManager localBluetoothManager,
ActivityStarter activityStarter,
- NotificationEntryManager entryManager
+ NotificationEntryManager entryManager,
+ UiEventLogger uiEventLogger
) {
super(context, attrs, dumpManager, broadcastDispatcher, qsLogger,
foregroundExecutor, backgroundExecutor, localBluetoothManager, activityStarter,
- entryManager);
+ entryManager, uiEventLogger);
if (mFooter != null) {
removeView(mFooter.getView());
}
@@ -118,9 +120,9 @@
lp2.setMarginStart(0);
mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2);
- mTileLayout = new DoubleLineTileLayout(context);
+ mTileLayout = new DoubleLineTileLayout(context, mUiEventLogger);
mMediaTileLayout = mTileLayout;
- mRegularTileLayout = new HeaderTileLayout(context);
+ mRegularTileLayout = new HeaderTileLayout(context, mUiEventLogger);
LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
lp.setMarginEnd(0);
lp.setMarginStart(marginSize);
@@ -135,7 +137,7 @@
super.setPadding(0, 0, 0, 0);
} else {
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
- mTileLayout = new HeaderTileLayout(context);
+ mTileLayout = new HeaderTileLayout(context, mUiEventLogger);
mTileLayout.setListening(mListening);
addView((View) mTileLayout, 0 /* Between brightness and footer */);
super.setPadding(0, 0, 0, 0);
@@ -312,13 +314,30 @@
super.setVisibility(visibility);
}
+ @Override
+ protected QSEvent openPanelEvent() {
+ return QSEvent.QQS_PANEL_EXPANDED;
+ }
+
+ @Override
+ protected QSEvent closePanelEvent() {
+ return QSEvent.QQS_PANEL_COLLAPSED;
+ }
+
+ @Override
+ protected QSEvent tileVisibleEvent() {
+ return QSEvent.QQS_TILE_VISIBLE;
+ }
+
private static class HeaderTileLayout extends TileLayout {
- private boolean mListening;
+ private final UiEventLogger mUiEventLogger;
+
private Rect mClippingBounds = new Rect();
- public HeaderTileLayout(Context context) {
+ public HeaderTileLayout(Context context, UiEventLogger uiEventLogger) {
super(context);
+ mUiEventLogger = uiEventLogger;
setClipChildren(false);
setClipToPadding(false);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
@@ -443,5 +462,18 @@
}
return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal);
}
+
+ @Override
+ public void setListening(boolean listening) {
+ boolean startedListening = !mListening && listening;
+ super.setListening(listening);
+ if (startedListening) {
+ for (int i = 0; i < getNumVisibleTiles(); i++) {
+ QSTile tile = mRecords.get(i).tile;
+ mUiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0,
+ tile.getMetricsSpec(), tile.getInstanceId());
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 90dc38f..b15c6a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -138,6 +138,7 @@
private Clock mClockView;
private DateView mDateView;
private BatteryMeterView mBatteryRemainingIcon;
+ private RingerModeTracker mRingerModeTracker;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@@ -159,10 +160,7 @@
mDualToneHandler = new DualToneHandler(
new ContextThemeWrapper(context, R.style.QSHeaderTheme));
mCommandQueue = commandQueue;
- ringerModeTracker.getRingerModeInternal().observe(this, ringer -> {
- mRingerMode = ringer;
- updateStatusText();
- });
+ mRingerModeTracker = ringerModeTracker;
}
@Override
@@ -429,6 +427,10 @@
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
+ mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> {
+ mRingerMode = ringer;
+ updateStatusText();
+ });
mStatusBarIconController.addIconGroup(mIconManager);
requestApplyInsets();
}
@@ -466,6 +468,7 @@
@VisibleForTesting
public void onDetachedFromWindow() {
setListening(false);
+ mRingerModeTracker.getRingerModeInternal().removeObservers(this);
mStatusBarIconController.removeIconGroup(mIconManager);
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index c2246396..65d81505 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -88,4 +88,12 @@
public int getCurrentUser() {
return mUserId;
}
+
+ public String getKey() {
+ return mSettingName;
+ }
+
+ public boolean isListening() {
+ return mListening;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 9f59277..0984316 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -31,7 +31,7 @@
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mCellMarginTop;
- private boolean mListening;
+ protected boolean mListening;
protected int mMaxAllowedRows = 3;
// Prototyping with less rows
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index bfac85b..3e2f9de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -44,6 +44,7 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSDetailClipper;
+import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -93,7 +94,8 @@
LightBarController lightBarController,
KeyguardStateController keyguardStateController,
ScreenLifecycle screenLifecycle,
- TileQueryHelper tileQueryHelper) {
+ TileQueryHelper tileQueryHelper,
+ UiEventLogger uiEventLogger) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
@@ -115,7 +117,7 @@
mToolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
- mTileAdapter = new TileAdapter(getContext());
+ mTileAdapter = new TileAdapter(getContext(), uiEventLogger);
mTileQueryHelper = tileQueryHelper;
mTileQueryHelper.setListener(mTileAdapter);
mRecyclerView.setAdapter(mTileAdapter);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt
deleted file mode 100644
index ff8ddec..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs.customize
-
-import com.android.internal.logging.UiEvent
-import com.android.internal.logging.UiEventLogger
-
-enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
-
- @UiEvent(doc = "Tile removed from current tiles")
- QS_EDIT_REMOVE(210),
- @UiEvent(doc = "Tile added to current tiles")
- QS_EDIT_ADD(211),
- @UiEvent(doc = "Tile moved")
- QS_EDIT_MOVE(212),
- @UiEvent(doc = "QS customizer open")
- QS_EDIT_OPEN(213),
- @UiEvent(doc = "QS customizer closed")
- QS_EDIT_CLOSED(214),
- @UiEvent(doc = "QS tiles reset")
- QS_EDIT_RESET(215);
-
- override fun getId() = _id
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 58de95d..e738cec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,8 +41,8 @@
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
+import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
@@ -92,10 +92,11 @@
private int mAccessibilityFromIndex;
private CharSequence mAccessibilityFromLabel;
private QSTileHost mHost;
- private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+ private final UiEventLogger mUiEventLogger;
- public TileAdapter(Context context) {
+ public TileAdapter(Context context, UiEventLogger uiEventLogger) {
mContext = context;
+ mUiEventLogger = uiEventLogger;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
mDecoration = new TileItemDecoration(context);
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 08c8f86..30e0a76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -371,6 +371,11 @@
return MetricsEvent.QS_CUSTOM;
}
+ @Override
+ public final String getMetricsSpec() {
+ return mComponent.getPackageName();
+ }
+
public void startUnlockAndRun() {
Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 8feee10..f821b19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -18,8 +18,10 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
@@ -64,6 +66,8 @@
private boolean mTileState;
private boolean mCollapsedView;
private boolean mShowRippleEffect = true;
+ private float mStrokeWidthActive;
+ private float mStrokeWidthInactive;
private final ImageView mBg;
private final TextView mDetailText;
@@ -83,6 +87,10 @@
// Default to Quick Tile padding, and QSTileView will specify its own padding.
int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
mIconFrame = new FrameLayout(context);
+ mStrokeWidthActive = context.getResources()
+ .getDimension(com.android.internal.R.dimen.config_qsTileStrokeWidthActive);
+ mStrokeWidthInactive = context.getResources()
+ .getDimension(com.android.internal.R.dimen.config_qsTileStrokeWidthInactive);
int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
addView(mIconFrame, new LayoutParams(size, size));
mBg = new ImageView(getContext());
@@ -206,7 +214,31 @@
mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
}
+ private void updateStrokeShapeWidth(QSTile.State state) {
+ Resources resources = getContext().getResources();
+ if (!(mBg.getDrawable() instanceof ShapeDrawable)) {
+ return;
+ }
+ ShapeDrawable d = (ShapeDrawable) mBg.getDrawable();
+ d.getPaint().setStyle(Paint.Style.FILL);
+ switch (state.state) {
+ case Tile.STATE_INACTIVE:
+ if (mStrokeWidthInactive >= 0) {
+ d.getPaint().setStyle(Paint.Style.STROKE);
+ d.getPaint().setStrokeWidth(mStrokeWidthInactive);
+ }
+ break;
+ case Tile.STATE_ACTIVE:
+ if (mStrokeWidthActive >= 0) {
+ d.getPaint().setStyle(Paint.Style.STROKE);
+ d.getPaint().setStrokeWidth(mStrokeWidthActive);
+ }
+ break;
+ }
+ }
+
protected void handleStateChanged(QSTile.State state) {
+ updateStrokeShapeWidth(state);
int circleColor = getCircleColor(state.state);
boolean allowAnimations = animationsEnabled();
if (circleColor != mCircleColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 60f6647..7e5f2e19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -48,7 +48,9 @@
import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
@@ -62,6 +64,7 @@
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.PagedTileLayout.TilePage;
+import com.android.systemui.qs.QSEvent;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.logging.QSLogger;
@@ -97,12 +100,14 @@
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final StatusBarStateController
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+ private final UiEventLogger mUiEventLogger;
private final QSLogger mQSLogger;
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Object mStaleListener = new Object();
protected TState mState;
private TState mTmpState;
+ private final InstanceId mInstanceId;
private boolean mAnnounceNextStateChange;
private String mTileSpec;
@@ -156,10 +161,12 @@
protected QSTileImpl(QSHost host) {
mHost = host;
mContext = host.getContext();
+ mInstanceId = host.getNewInstanceId();
mState = newTileState();
mTmpState = newTileState();
mQSSettingsPanelOption = QSSettingsControllerKt.getQSSettingsPanelOption();
mQSLogger = host.getQSLogger();
+ mUiEventLogger = host.getUiEventLogger();
}
protected final void resetStates() {
@@ -173,6 +180,11 @@
return mLifecycle;
}
+ @Override
+ public InstanceId getInstanceId() {
+ return mInstanceId;
+ }
+
/**
* Adds or removes a listening client for the tile. If the tile has one or more
* listening client it will go into the listening state.
@@ -247,6 +259,8 @@
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)
.addTaggedData(FIELD_STATUS_BAR_STATE,
mStatusBarStateController.getState())));
+ mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_CLICK, 0, getMetricsSpec(),
+ getInstanceId());
mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
mHandler.sendEmptyMessage(H.CLICK);
}
@@ -255,6 +269,8 @@
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)
.addTaggedData(FIELD_STATUS_BAR_STATE,
mStatusBarStateController.getState())));
+ mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_SECONDARY_CLICK, 0, getMetricsSpec(),
+ getInstanceId());
mQSLogger.logTileSecondaryClick(mTileSpec, mStatusBarStateController.getState(),
mState.state);
mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
@@ -264,6 +280,8 @@
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)
.addTaggedData(FIELD_STATUS_BAR_STATE,
mStatusBarStateController.getState())));
+ mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_LONG_PRESS, 0, getMetricsSpec(),
+ getInstanceId());
mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
mHandler.sendEmptyMessage(H.LONG_CLICK);
@@ -483,6 +501,11 @@
}
}
+ @Override
+ public String getMetricsSpec() {
+ return mTileSpec;
+ }
+
/**
* Provides a default label for the tile.
* @return default label for the tile.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 447f48b..89ce125 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -26,10 +26,12 @@
import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
+import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
@@ -48,8 +50,9 @@
R.layout.qs_user_detail, parent, attach);
}
- public void createAndSetAdapter(UserSwitcherController controller) {
- mAdapter = new Adapter(mContext, controller);
+ public void createAndSetAdapter(UserSwitcherController controller,
+ UiEventLogger uiEventLogger) {
+ mAdapter = new Adapter(mContext, controller, uiEventLogger);
ViewGroupAdapterBridge.link(this, mAdapter);
}
@@ -63,11 +66,14 @@
private final Context mContext;
protected UserSwitcherController mController;
private View mCurrentUserView;
+ private final UiEventLogger mUiEventLogger;
- public Adapter(Context context, UserSwitcherController controller) {
+ public Adapter(Context context, UserSwitcherController controller,
+ UiEventLogger uiEventLogger) {
super(controller);
mContext = context;
mController = controller;
+ mUiEventLogger = uiEventLogger;
}
@Override
@@ -127,6 +133,7 @@
mController.startActivity(intent);
} else if (tag.isSwitchToEnabled) {
MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
+ mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH);
if (!tag.isAddUser && !tag.isRestricted && !tag.isDisabledByAdmin) {
if (mCurrentUserView != null) {
mCurrentUserView.setActivated(false);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index ae0a1c4..b253635 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -137,7 +137,7 @@
* Check if the recording is ongoing
* @return
*/
- public boolean isRecording() {
+ public synchronized boolean isRecording() {
return mIsRecording;
}
@@ -157,7 +157,7 @@
* Update the current status
* @param isRecording
*/
- public void updateState(boolean isRecording) {
+ public synchronized void updateState(boolean isRecording) {
mIsRecording = isRecording;
for (RecordingStateChangeCallback cb : mListeners) {
if (isRecording) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 390ac09..cf098d5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -22,41 +22,27 @@
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
-import android.media.projection.IMediaProjection;
-import android.media.projection.IMediaProjectionManager;
-import android.media.projection.MediaProjection;
-import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.MediaStore;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
-import android.view.Surface;
-import android.view.WindowManager;
import android.widget.Toast;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.LongRunning;
-import java.io.File;
import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -66,13 +52,15 @@
public class RecordingService extends Service implements MediaRecorder.OnInfoListener {
public static final int REQUEST_CODE = 2;
- private static final int NOTIFICATION_ID = 1;
+ private static final int NOTIFICATION_RECORDING_ID = 4274;
+ private static final int NOTIFICATION_PROCESSING_ID = 4275;
+ private static final int NOTIFICATION_VIEW_ID = 4273;
private static final String TAG = "RecordingService";
private static final String CHANNEL_ID = "screen_record";
private static final String EXTRA_RESULT_CODE = "extra_resultCode";
private static final String EXTRA_DATA = "extra_data";
private static final String EXTRA_PATH = "extra_path";
- private static final String EXTRA_USE_AUDIO = "extra_useAudio";
+ private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
private static final String ACTION_START = "com.android.systemui.screenrecord.START";
@@ -80,29 +68,19 @@
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
- private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 10000000;
- private static final int VIDEO_FRAME_RATE = 30;
- private static final int AUDIO_BIT_RATE = 16;
- private static final int AUDIO_SAMPLE_RATE = 44100;
- private static final int MAX_DURATION_MS = 60 * 60 * 1000;
- private static final long MAX_FILESIZE_BYTES = 5000000000L;
-
private final RecordingController mController;
- private MediaProjection mMediaProjection;
- private Surface mInputSurface;
- private VirtualDisplay mVirtualDisplay;
- private MediaRecorder mMediaRecorder;
private Notification.Builder mRecordingNotificationBuilder;
- private boolean mUseAudio;
+ private ScreenRecordingAudioSource mAudioSource;
private boolean mShowTaps;
private boolean mOriginalShowTaps;
- private File mTempFile;
+ private ScreenMediaRecorder mRecorder;
+ private final Executor mLongExecutor;
@Inject
- public RecordingService(RecordingController controller) {
+ public RecordingService(RecordingController controller, @LongRunning Executor executor) {
mController = controller;
+ mLongExecutor = executor;
}
/**
@@ -113,16 +91,16 @@
* android.content.Intent)}
* @param data The data from {@link android.app.Activity#onActivityResult(int, int,
* android.content.Intent)}
- * @param useAudio True to enable microphone input while recording
+ * @param audioSource The ordinal value of the audio source
+ * {@link com.android.systemui.screenrecord.ScreenRecordingAudioSource}
* @param showTaps True to make touches visible while recording
*/
- public static Intent getStartIntent(Context context, int resultCode, Intent data,
- boolean useAudio, boolean showTaps) {
+ public static Intent getStartIntent(Context context, int resultCode,
+ int audioSource, boolean showTaps) {
return new Intent(context, RecordingService.class)
.setAction(ACTION_START)
.putExtra(EXTRA_RESULT_CODE, resultCode)
- .putExtra(EXTRA_DATA, data)
- .putExtra(EXTRA_USE_AUDIO, useAudio)
+ .putExtra(EXTRA_AUDIO_SOURCE, audioSource)
.putExtra(EXTRA_SHOW_TAPS, showTaps);
}
@@ -139,36 +117,31 @@
switch (action) {
case ACTION_START:
- mUseAudio = intent.getBooleanExtra(EXTRA_USE_AUDIO, false);
+ mAudioSource = ScreenRecordingAudioSource
+ .values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)];
+ Log.d(TAG, "recording with audio source" + mAudioSource);
mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false);
- try {
- IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
- IMediaProjectionManager mediaService =
- IMediaProjectionManager.Stub.asInterface(b);
- IMediaProjection proj = mediaService.createProjection(getUserId(),
- getPackageName(),
- MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
- IBinder projection = proj.asBinder();
- if (projection == null) {
- Log.e(TAG, "Projection was null");
- Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
- .show();
- return Service.START_NOT_STICKY;
- }
- mMediaProjection = new MediaProjection(getApplicationContext(),
- IMediaProjection.Stub.asInterface(projection));
- startRecording();
- } catch (RemoteException e) {
- e.printStackTrace();
- Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG)
- .show();
- return Service.START_NOT_STICKY;
- }
+
+ mOriginalShowTaps = Settings.System.getInt(
+ getApplicationContext().getContentResolver(),
+ Settings.System.SHOW_TOUCHES, 0) != 0;
+
+ setTapsVisible(mShowTaps);
+
+ mRecorder = new ScreenMediaRecorder(
+ getApplicationContext(),
+ getUserId(),
+ mAudioSource,
+ this
+ );
+ startRecording();
break;
case ACTION_STOP:
stopRecording();
+ notificationManager.cancel(NOTIFICATION_RECORDING_ID);
saveRecording(notificationManager);
+ stopSelf();
break;
case ACTION_SHARE:
@@ -183,10 +156,10 @@
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
// Remove notification
- notificationManager.cancel(NOTIFICATION_ID);
+ notificationManager.cancel(NOTIFICATION_RECORDING_ID);
startActivity(Intent.createChooser(shareIntent, shareLabel)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
break;
case ACTION_DELETE:
// Close quick shade
@@ -202,7 +175,7 @@
Toast.LENGTH_LONG).show();
// Remove notification
- notificationManager.cancel(NOTIFICATION_ID);
+ notificationManager.cancel(NOTIFICATION_RECORDING_ID);
Log.d(TAG, "Deleted recording " + uri);
break;
}
@@ -224,70 +197,15 @@
*/
private void startRecording() {
try {
- File cacheDir = getCacheDir();
- cacheDir.mkdirs();
- mTempFile = File.createTempFile("temp", ".mp4", cacheDir);
- Log.d(TAG, "Writing video output to: " + mTempFile.getAbsolutePath());
-
- mOriginalShowTaps = 1 == Settings.System.getInt(
- getApplicationContext().getContentResolver(),
- Settings.System.SHOW_TOUCHES, 0);
- setTapsVisible(mShowTaps);
-
- // Set up media recorder
- mMediaRecorder = new MediaRecorder();
- if (mUseAudio) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- }
- mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
-
- // Set up video
- DisplayMetrics metrics = new DisplayMetrics();
- WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getRealMetrics(metrics);
- int screenWidth = metrics.widthPixels;
- int screenHeight = metrics.heightPixels;
- mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- mMediaRecorder.setVideoSize(screenWidth, screenHeight);
- mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
- mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
- mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
- mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
-
- // Set up audio
- if (mUseAudio) {
- mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
- mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
- mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
- }
-
- mMediaRecorder.setOutputFile(mTempFile);
- mMediaRecorder.prepare();
-
- // Create surface
- mInputSurface = mMediaRecorder.getSurface();
- mVirtualDisplay = mMediaProjection.createVirtualDisplay(
- "Recording Display",
- screenWidth,
- screenHeight,
- metrics.densityDpi,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
- mInputSurface,
- null,
- null);
-
- mMediaRecorder.setOnInfoListener(this);
- mMediaRecorder.start();
+ mRecorder.start();
mController.updateState(true);
- } catch (IOException e) {
- Log.e(TAG, "Error starting screen recording: " + e.getMessage());
+ createRecordingNotification();
+ } catch (IOException | RemoteException e) {
+ Toast.makeText(this,
+ R.string.screenrecord_start_error, Toast.LENGTH_LONG)
+ .show();
e.printStackTrace();
- throw new RuntimeException(e);
}
-
- createRecordingNotification();
}
private void createRecordingNotification() {
@@ -306,7 +224,7 @@
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_name));
- String notificationTitle = mUseAudio
+ String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
: res.getString(R.string.screenrecord_ongoing_screen_only);
@@ -323,9 +241,10 @@
this, REQUEST_CODE, getStopIntent(this),
PendingIntent.FLAG_UPDATE_CURRENT))
.addExtras(extras);
- notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build());
+ notificationManager.notify(NOTIFICATION_RECORDING_ID,
+ mRecordingNotificationBuilder.build());
Notification notification = mRecordingNotificationBuilder.build();
- startForeground(NOTIFICATION_ID, notification);
+ startForeground(NOTIFICATION_RECORDING_ID, notification);
}
private Notification createSaveNotification(Uri uri) {
@@ -392,47 +311,38 @@
private void stopRecording() {
setTapsVisible(mOriginalShowTaps);
- mMediaRecorder.stop();
- mMediaRecorder.release();
- mMediaRecorder = null;
- mMediaProjection.stop();
- mMediaProjection = null;
- mInputSurface.release();
- mVirtualDisplay.release();
- stopSelf();
+ mRecorder.end();
mController.updateState(false);
}
private void saveRecording(NotificationManager notificationManager) {
- String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
- .format(new Date());
+ Resources res = getApplicationContext().getResources();
+ String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+ Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+ .setContentTitle(notificationTitle)
+ .setContentText(
+ getResources().getString(R.string.screenrecord_background_processing_label))
+ .setSmallIcon(R.drawable.ic_screenrecord);
+ notificationManager.notify(NOTIFICATION_PROCESSING_ID, builder.build());
- ContentValues values = new ContentValues();
- values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
- values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
- values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
- values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
-
- ContentResolver resolver = getContentResolver();
- Uri collectionUri = MediaStore.Video.Media.getContentUri(
- MediaStore.VOLUME_EXTERNAL_PRIMARY);
- Uri itemUri = resolver.insert(collectionUri, values);
-
- try {
- // Add to the mediastore
- OutputStream os = resolver.openOutputStream(itemUri, "w");
- Files.copy(mTempFile.toPath(), os);
- os.close();
-
- Notification notification = createSaveNotification(itemUri);
- notificationManager.notify(NOTIFICATION_ID, notification);
-
- mTempFile.delete();
- } catch (IOException e) {
- Log.e(TAG, "Error saving screen recording: " + e.getMessage());
- Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
- .show();
- }
+ mLongExecutor.execute(() -> {
+ try {
+ Log.d(TAG, "saving recording");
+ Notification notification = createSaveNotification(mRecorder.save());
+ if (!mController.isRecording()) {
+ Log.d(TAG, "showing saved notification");
+ notificationManager.notify(NOTIFICATION_VIEW_ID, notification);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error saving screen recording: " + e.getMessage());
+ Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
+ .show();
+ } finally {
+ notificationManager.cancel(NOTIFICATION_PROCESSING_ID);
+ }
+ });
}
private void setTapsVisible(boolean turnOn) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
new file mode 100644
index 0000000..752f4fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenrecord;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioPlaybackCaptureConfiguration;
+import android.media.AudioRecord;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.media.MediaRecorder;
+import android.media.projection.MediaProjection;
+import android.util.Log;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Recording internal audio
+ */
+public class ScreenInternalAudioRecorder {
+ private static String TAG = "ScreenAudioRecorder";
+ private static final int TIMEOUT = 500;
+ private final Context mContext;
+ private AudioRecord mAudioRecord;
+ private AudioRecord mAudioRecordMic;
+ private Config mConfig = new Config();
+ private Thread mThread;
+ private MediaProjection mMediaProjection;
+ private MediaCodec mCodec;
+ private long mPresentationTime;
+ private long mTotalBytes;
+ private MediaMuxer mMuxer;
+ private String mOutFile;
+ private boolean mMic;
+
+ private int mTrackId = -1;
+
+ public ScreenInternalAudioRecorder(String outFile, Context context,
+ MediaProjection mp, boolean includeMicInput) throws IOException {
+ mMic = includeMicInput;
+ mOutFile = outFile;
+ mMuxer = new MediaMuxer(outFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ mContext = context;
+ mMediaProjection = mp;
+ Log.d(TAG, "creating audio file " + outFile);
+ setupSimple();
+ }
+ /**
+ * Audio recoding configuration
+ */
+ public static class Config {
+ public int channelOutMask = AudioFormat.CHANNEL_OUT_MONO;
+ public int channelInMask = AudioFormat.CHANNEL_IN_MONO;
+ public int encoding = AudioFormat.ENCODING_PCM_16BIT;
+ public int sampleRate = 44100;
+ public int bitRate = 196000;
+ public int bufferSizeBytes = 1 << 17;
+ public boolean privileged = true;
+ public boolean legacy_app_looback = false;
+
+ @Override
+ public String toString() {
+ return "channelMask=" + channelOutMask
+ + "\n encoding=" + encoding
+ + "\n sampleRate=" + sampleRate
+ + "\n bufferSize=" + bufferSizeBytes
+ + "\n privileged=" + privileged
+ + "\n legacy app looback=" + legacy_app_looback;
+ }
+
+ }
+
+ private void setupSimple() throws IOException {
+ int size = AudioRecord.getMinBufferSize(
+ mConfig.sampleRate, mConfig.channelInMask,
+ mConfig.encoding) * 2;
+
+ Log.d(TAG, "audio buffer size: " + size);
+
+ AudioFormat format = new AudioFormat.Builder()
+ .setEncoding(mConfig.encoding)
+ .setSampleRate(mConfig.sampleRate)
+ .setChannelMask(mConfig.channelOutMask)
+ .build();
+
+ AudioPlaybackCaptureConfiguration playbackConfig =
+ new AudioPlaybackCaptureConfiguration.Builder(mMediaProjection)
+ .addMatchingUsage(AudioAttributes.USAGE_MEDIA)
+ .addMatchingUsage(AudioAttributes.USAGE_UNKNOWN)
+ .addMatchingUsage(AudioAttributes.USAGE_GAME)
+ .build();
+
+ mAudioRecord = new AudioRecord.Builder()
+ .setAudioFormat(format)
+ .setAudioPlaybackCaptureConfig(playbackConfig)
+ .build();
+
+ if (mMic) {
+ mAudioRecordMic = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
+ mConfig.sampleRate, AudioFormat.CHANNEL_IN_MONO, mConfig.encoding, size);
+ }
+
+ mCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
+ MediaFormat medFormat = MediaFormat.createAudioFormat(
+ MediaFormat.MIMETYPE_AUDIO_AAC, mConfig.sampleRate, 1);
+ medFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
+ MediaCodecInfo.CodecProfileLevel.AACObjectLC);
+ medFormat.setInteger(MediaFormat.KEY_BIT_RATE, mConfig.bitRate);
+ medFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, mConfig.encoding);
+ mCodec.configure(medFormat,
+ null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+ mThread = new Thread(() -> {
+ short[] bufferInternal = null;
+ short[] bufferMic = null;
+ byte[] buffer = null;
+
+ if (mMic) {
+ bufferInternal = new short[size / 2];
+ bufferMic = new short[size / 2];
+ } else {
+ buffer = new byte[size];
+ }
+
+ while (true) {
+ int readBytes = 0;
+ int readShortsInternal = 0;
+ int readShortsMic = 0;
+ if (mMic) {
+ readShortsInternal = mAudioRecord.read(bufferInternal, 0,
+ bufferInternal.length);
+ readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+ readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
+ buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
+ readShortsMic);
+ } else {
+ readBytes = mAudioRecord.read(buffer, 0, buffer.length);
+ }
+
+ //exit the loop when at end of stream
+ if (readBytes < 0) {
+ Log.e(TAG, "read error " + readBytes +
+ ", shorts internal: " + readShortsInternal +
+ ", shorts mic: " + readShortsMic);
+ break;
+ }
+ encode(buffer, readBytes);
+ }
+ endStream();
+ });
+ }
+
+ private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
+ int size = Math.max(a1Limit, a2Limit);
+ if (size < 0) return new byte[0];
+ byte[] buff = new byte[size * 2];
+ for (int i = 0; i < size; i++) {
+ int sum;
+ if (i > a1Limit) {
+ sum = a2[i];
+ } else if (i > a2Limit) {
+ sum = a1[i];
+ } else {
+ sum = (int) a1[i] + (int) a2[i];
+ }
+
+ if (sum > Short.MAX_VALUE) sum = Short.MAX_VALUE;
+ if (sum < Short.MIN_VALUE) sum = Short.MIN_VALUE;
+ int byteIndex = i * 2;
+ buff[byteIndex] = (byte) (sum & 0xff);
+ buff[byteIndex + 1] = (byte) ((sum >> 8) & 0xff);
+ }
+ return buff;
+ }
+
+ private void encode(byte[] buffer, int readBytes) {
+ int offset = 0;
+ while (readBytes > 0) {
+ int totalBytesRead = 0;
+ int bufferIndex = mCodec.dequeueInputBuffer(TIMEOUT);
+ if (bufferIndex < 0) {
+ writeOutput();
+ return;
+ }
+ ByteBuffer buff = mCodec.getInputBuffer(bufferIndex);
+ buff.clear();
+ int bufferSize = buff.capacity();
+ int bytesToRead = readBytes > bufferSize ? bufferSize : readBytes;
+ totalBytesRead += bytesToRead;
+ readBytes -= bytesToRead;
+ buff.put(buffer, offset, bytesToRead);
+ offset += bytesToRead;
+ mCodec.queueInputBuffer(bufferIndex, 0, bytesToRead, mPresentationTime, 0);
+ mTotalBytes += totalBytesRead;
+ mPresentationTime = 1000000L * (mTotalBytes / 2) / mConfig.sampleRate;
+
+ writeOutput();
+ }
+ }
+
+ private void endStream() {
+ int bufferIndex = mCodec.dequeueInputBuffer(TIMEOUT);
+ mCodec.queueInputBuffer(bufferIndex, 0, 0, mPresentationTime,
+ MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ writeOutput();
+ }
+
+ private void writeOutput() {
+ while (true) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ int bufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT);
+ if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mTrackId = mMuxer.addTrack(mCodec.getOutputFormat());
+ mMuxer.start();
+ continue;
+ }
+ if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ break;
+ }
+ if (mTrackId < 0) return;
+ ByteBuffer buff = mCodec.getOutputBuffer(bufferIndex);
+
+ if (!((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0
+ && bufferInfo.size != 0)) {
+ mMuxer.writeSampleData(mTrackId, buff, bufferInfo);
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ }
+ }
+
+ /**
+ * start recording
+ */
+ public void start() {
+ if (mThread != null) {
+ Log.e(TAG, "a recording is being done in parallel or stop is not called");
+ }
+ mAudioRecord.startRecording();
+ if (mMic) mAudioRecordMic.startRecording();
+ Log.d(TAG, "channel count " + mAudioRecord.getChannelCount());
+ mCodec.start();
+ if (mAudioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+ Log.e(TAG, "Error starting audio recording");
+ return;
+ }
+ mThread.start();
+ }
+
+ /**
+ * end recording
+ */
+ public void end() {
+ mAudioRecord.stop();
+ if (mMic) {
+ mAudioRecordMic.stop();
+ }
+ mAudioRecord.release();
+ if (mMic) {
+ mAudioRecordMic.release();
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mCodec.stop();
+ mCodec.release();
+ mMuxer.stop();
+ mMuxer.release();
+ mThread = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
new file mode 100644
index 0000000..c967648
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenrecord;
+
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
+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.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.MediaMuxer;
+import android.media.MediaRecorder;
+import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjection;
+import android.media.projection.MediaProjectionManager;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.MediaStore;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Recording screen and mic/internal audio
+ */
+public class ScreenMediaRecorder {
+ private static final int TOTAL_NUM_TRACKS = 1;
+ private static final int VIDEO_BIT_RATE = 10000000;
+ private static final int VIDEO_FRAME_RATE = 30;
+ private static final int AUDIO_BIT_RATE = 16;
+ private static final int AUDIO_SAMPLE_RATE = 44100;
+ private static final int MAX_DURATION_MS = 60 * 60 * 1000;
+ private static final long MAX_FILESIZE_BYTES = 5000000000L;
+ private static final String TAG = "ScreenMediaRecorder";
+
+
+ private File mTempVideoFile;
+ private File mTempAudioFile;
+ private MediaProjection mMediaProjection;
+ private Surface mInputSurface;
+ private VirtualDisplay mVirtualDisplay;
+ private MediaRecorder mMediaRecorder;
+ private int mUser;
+ private ScreenRecordingMuxer mMuxer;
+ private ScreenInternalAudioRecorder mAudio;
+ private ScreenRecordingAudioSource mAudioSource;
+
+ private Context mContext;
+ MediaRecorder.OnInfoListener mListener;
+
+ public ScreenMediaRecorder(Context context,
+ int user, ScreenRecordingAudioSource audioSource,
+ MediaRecorder.OnInfoListener listener) {
+ mContext = context;
+ mUser = user;
+ mListener = listener;
+ mAudioSource = audioSource;
+ }
+
+ private void prepare() throws IOException, RemoteException {
+ //Setup media projection
+ IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
+ IMediaProjectionManager mediaService =
+ IMediaProjectionManager.Stub.asInterface(b);
+ IMediaProjection proj = null;
+ proj = mediaService.createProjection(mUser, mContext.getPackageName(),
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
+ IBinder projection = proj.asBinder();
+ mMediaProjection = new MediaProjection(mContext,
+ IMediaProjection.Stub.asInterface(projection));
+
+ File cacheDir = mContext.getCacheDir();
+ cacheDir.mkdirs();
+ mTempVideoFile = File.createTempFile("temp", ".mp4", cacheDir);
+
+ // Set up media recorder
+ mMediaRecorder = new MediaRecorder();
+
+ // Set up audio source
+ if (mAudioSource == MIC) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+
+
+ // Set up video
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getRealMetrics(metrics);
+ int screenWidth = metrics.widthPixels;
+ int screenHeight = metrics.heightPixels;
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setVideoSize(screenWidth, screenHeight);
+ mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
+ mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+ mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
+ mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
+
+ // Set up audio
+ if (mAudioSource == MIC) {
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
+ mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
+ mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
+ mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
+ }
+
+ mMediaRecorder.setOutputFile(mTempVideoFile);
+ mMediaRecorder.prepare();
+ // Create surface
+ mInputSurface = mMediaRecorder.getSurface();
+ mVirtualDisplay = mMediaProjection.createVirtualDisplay(
+ "Recording Display",
+ screenWidth,
+ screenHeight,
+ metrics.densityDpi,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+ mInputSurface,
+ null,
+ null);
+
+ mMediaRecorder.setOnInfoListener(mListener);
+ if (mAudioSource == INTERNAL ||
+ mAudioSource == MIC_AND_INTERNAL) {
+ mTempAudioFile = File.createTempFile("temp", ".aac",
+ mContext.getCacheDir());
+ mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(), mContext,
+ mMediaProjection, mAudioSource == MIC_AND_INTERNAL);
+ }
+
+ }
+
+ /**
+ * Start screen recording
+ */
+ void start() throws IOException, RemoteException {
+ Log.d(TAG, "start recording");
+ prepare();
+ mMediaRecorder.start();
+ recordInternalAudio();
+ }
+
+ /**
+ * End screen recording
+ */
+ void end() {
+ mMediaRecorder.stop();
+ mMediaProjection.stop();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ mMediaProjection = null;
+ mInputSurface.release();
+ mVirtualDisplay.release();
+ stopInternalAudioRecording();
+
+ Log.d(TAG, "end recording");
+ }
+
+ private void stopInternalAudioRecording() {
+ if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) {
+ mAudio.end();
+ mAudio = null;
+ }
+ }
+
+ private void recordInternalAudio() {
+ if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) {
+ mAudio.start();
+ }
+ }
+
+ /**
+ * Store recorded video
+ */
+ Uri save() throws IOException {
+ String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
+ .format(new Date());
+
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
+ values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
+ values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
+ values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+
+ ContentResolver resolver = mContext.getContentResolver();
+ Uri collectionUri = MediaStore.Video.Media.getContentUri(
+ MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ Uri itemUri = resolver.insert(collectionUri, values);
+
+ Log.d(TAG, itemUri.toString());
+ if (mAudioSource == MIC_AND_INTERNAL || mAudioSource == INTERNAL) {
+ try {
+ Log.d(TAG, "muxing recording");
+ File file = File.createTempFile("temp", ".mp4",
+ mContext.getCacheDir());
+ mMuxer = new ScreenRecordingMuxer(MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,
+ file.getAbsolutePath(),
+ mTempVideoFile.getAbsolutePath(),
+ mTempAudioFile.getAbsolutePath());
+ mMuxer.mux();
+ mTempVideoFile.delete();
+ mTempVideoFile = file;
+ } catch (IOException e) {
+ Log.e(TAG, "muxing recording " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ // Add to the mediastore
+ OutputStream os = resolver.openOutputStream(itemUri, "w");
+ Files.copy(mTempVideoFile.toPath(), os);
+ os.close();
+ mTempVideoFile.delete();
+ if (mTempAudioFile != null) mTempAudioFile.delete();
+ return itemUri;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index 26973d0..c2473280 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -16,17 +16,30 @@
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 static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE;
+
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Bundle;
+import android.util.Log;
import android.view.Gravity;
+import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.Spinner;
import android.widget.Switch;
import com.android.systemui.R;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.inject.Inject;
/**
@@ -35,10 +48,15 @@
public class ScreenRecordDialog extends Activity {
private static final long DELAY_MS = 3000;
private static final long INTERVAL_MS = 1000;
+ private static final String TAG = "ScreenRecordDialog";
private final RecordingController mController;
- private Switch mAudioSwitch;
private Switch mTapsSwitch;
+ private Switch mAudioSwitch;
+ private Spinner mOptions;
+ private List<ScreenRecordingAudioSource> mModes;
+ private int mSelected;
+
@Inject
public ScreenRecordDialog(RecordingController controller) {
@@ -68,17 +86,32 @@
finish();
});
+ mModes = new ArrayList<>();
+ mModes.add(INTERNAL);
+ mModes.add(MIC);
+ mModes.add(MIC_AND_INTERNAL);
+
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
mTapsSwitch = findViewById(R.id.screenrecord_taps_switch);
+ mOptions = findViewById(R.id.screen_recording_options);
+ ArrayAdapter a = new ScreenRecordingAdapter(getApplicationContext(),
+ android.R.layout.simple_spinner_dropdown_item,
+ mModes);
+ a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mOptions.setAdapter(a);
+
}
private void requestScreenCapture() {
- boolean useAudio = mAudioSwitch.isChecked();
boolean showTaps = mTapsSwitch.isChecked();
+ ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked()
+ ? (ScreenRecordingAudioSource) mOptions.getSelectedItem()
+ : NONE;
PendingIntent startIntent = PendingIntent.getForegroundService(this,
RecordingService.REQUEST_CODE,
RecordingService.getStartIntent(
- ScreenRecordDialog.this, RESULT_OK, null, useAudio, showTaps),
+ ScreenRecordDialog.this, RESULT_OK,
+ audioMode.ordinal(), showTaps),
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent stopIntent = PendingIntent.getService(this,
RecordingService.REQUEST_CODE,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
new file mode 100644
index 0000000..2e0e746
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.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;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.List;
+
+/**
+ * Screen recording view adapter
+ */
+public class ScreenRecordingAdapter extends ArrayAdapter<ScreenRecordingAudioSource> {
+ 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) {
+ super(context, resource, objects);
+ initViews();
+ }
+
+ private void initViews() {
+ 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);
+ 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);
+ return layout;
+ }
+
+ private LinearLayout getSelected(int label) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ LinearLayout layout = (LinearLayout) inflater
+ .inflate(R.layout.screen_record_dialog_audio_source_selected, null, false);
+ ((TextView) layout.findViewById(R.id.screen_recording_dialog_source_text))
+ .setText(label);
+ return layout;
+ }
+
+ private void setDescription(LinearLayout layout, int description) {
+ if (description != Resources.ID_NULL) {
+ ((TextView) layout.getChildAt(1)).setText(description);
+ }
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ switch (getItem(position)) {
+ case INTERNAL:
+ return mInternalOption;
+ case MIC_AND_INTERNAL:
+ return mMicAndInternalOption;
+ case MIC:
+ return mMicOption;
+ default:
+ return super.getDropDownView(position, convertView, parent);
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ switch (getItem(position)) {
+ case INTERNAL:
+ return mSelectedInternal;
+ case MIC_AND_INTERNAL:
+ return mSelectedMicAndInternal;
+ case MIC:
+ return mSelectedMic;
+ default:
+ return super.getView(position, convertView, parent);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java
new file mode 100644
index 0000000..ee11865
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAudioSource.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenrecord;
+
+/**
+ * Audio sources
+ */
+public enum ScreenRecordingAudioSource {
+ NONE,
+ INTERNAL,
+ MIC,
+ MIC_AND_INTERNAL;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
new file mode 100644
index 0000000..7ffcfd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenrecord;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaMuxer;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * Mixing audio and video tracks
+ */
+public class ScreenRecordingMuxer {
+ // size of a memory page for cache coherency
+ private static final int BUFFER_SIZE = 1024 * 4096;
+ private String[] mFiles;
+ private String mOutFile;
+ private int mFormat;
+ private ArrayMap<Pair<MediaExtractor, Integer>, Integer> mExtractorIndexToMuxerIndex
+ = new ArrayMap<>();
+ private ArrayList<MediaExtractor> mExtractors = new ArrayList<>();
+
+ private static String TAG = "ScreenRecordingMuxer";
+ public ScreenRecordingMuxer(@MediaMuxer.Format int format, String outfileName,
+ String... inputFileNames) {
+ mFiles = inputFileNames;
+ mOutFile = outfileName;
+ mFormat = format;
+ Log.d(TAG, "out: " + mOutFile + " , in: " + mFiles[0]);
+ }
+
+ /**
+ * RUN IN THE BACKGROUND THREAD!
+ */
+ public void mux() throws IOException {
+ MediaMuxer muxer = null;
+ muxer = new MediaMuxer(mOutFile, mFormat);
+ // Add extractors
+ for (String file: mFiles) {
+ MediaExtractor extractor = new MediaExtractor();
+ try {
+ extractor.setDataSource(file);
+ } catch (IOException e) {
+ Log.e(TAG, "error creating extractor: " + file);
+ e.printStackTrace();
+ continue;
+ }
+ Log.d(TAG, file + " track count: " + extractor.getTrackCount());
+ mExtractors.add(extractor);
+ for (int i = 0; i < extractor.getTrackCount(); i++) {
+ int muxId = muxer.addTrack(extractor.getTrackFormat(i));
+ Log.d(TAG, "created extractor format" + extractor.getTrackFormat(i).toString());
+ mExtractorIndexToMuxerIndex.put(Pair.create(extractor, i), muxId);
+ }
+ }
+
+ muxer.start();
+ for (Pair<MediaExtractor, Integer> pair: mExtractorIndexToMuxerIndex.keySet()) {
+ MediaExtractor extractor = pair.first;
+ extractor.selectTrack(pair.second);
+ int muxId = mExtractorIndexToMuxerIndex.get(pair);
+ Log.d(TAG, "track format: " + extractor.getTrackFormat(pair.second));
+ extractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ int offset;
+ while (true) {
+ offset = buffer.arrayOffset();
+ info.size = extractor.readSampleData(buffer, offset);
+ if (info.size < 0) break;
+ info.presentationTimeUs = extractor.getSampleTime();
+ info.flags = extractor.getSampleFlags();
+ muxer.writeSampleData(muxId, buffer, info);
+ extractor.advance();
+ }
+ }
+
+ for (MediaExtractor extractor: mExtractors) {
+ extractor.release();
+ }
+ muxer.stop();
+ muxer.release();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 5814221..4148289 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -17,7 +17,6 @@
package com.android.systemui.screenshot;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED;
@@ -72,7 +71,6 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
@@ -187,10 +185,11 @@
private final View mScreenshotLayout;
private final ScreenshotSelectorView mScreenshotSelectorView;
- private final ImageView mBackgroundView;
- private final ImageView mScreenshotView;
+ private final ImageView mScreenshotAnimatedView;
+ private final ImageView mScreenshotPreview;
private final ImageView mScreenshotFlash;
- private final HorizontalScrollView mActionsContainer;
+ private final ImageView mActionsContainerBackground;
+ private final FrameLayout mActionsContainer;
private final LinearLayout mActionsView;
private final ImageView mBackgroundProtection;
private final FrameLayout mDismissButton;
@@ -205,8 +204,6 @@
private float mScreenshotOffsetXPx;
private float mScreenshotOffsetYPx;
- private float mScreenshotHeightPx;
- private float mDismissButtonSize;
private float mCornerSizeX;
private float mDismissDeltaY;
@@ -244,10 +241,19 @@
// Inflate the screenshot layout
mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
- mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background);
- mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot);
- mScreenshotView.setClipToOutline(true);
- mScreenshotView.setOutlineProvider(new ViewOutlineProvider() {
+ mScreenshotAnimatedView =
+ mScreenshotLayout.findViewById(R.id.global_screenshot_animated_view);
+ mScreenshotAnimatedView.setClipToOutline(true);
+ mScreenshotAnimatedView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
+ ROUNDED_CORNER_RADIUS * view.getWidth());
+ }
+ });
+ mScreenshotPreview = mScreenshotLayout.findViewById(R.id.global_screenshot_preview);
+ mScreenshotPreview.setClipToOutline(true);
+ mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
@@ -255,6 +261,8 @@
}
});
+ mActionsContainerBackground = mScreenshotLayout.findViewById(
+ R.id.global_screenshot_actions_container_background);
mActionsContainer = mScreenshotLayout.findViewById(
R.id.global_screenshot_actions_container);
mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions);
@@ -273,9 +281,8 @@
mScreenshotLayout.setFocusable(true);
mScreenshotSelectorView.setFocusable(true);
mScreenshotSelectorView.setFocusableInTouchMode(true);
- mScreenshotView.setPivotX(0);
- mScreenshotView.setPivotY(0);
- mActionsContainer.setPivotX(0);
+ mScreenshotAnimatedView.setPivotX(0);
+ mScreenshotAnimatedView.setPivotY(0);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -297,10 +304,6 @@
mScreenshotOffsetXPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_x);
mScreenshotOffsetYPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_y);
- mScreenshotHeightPx =
- resources.getDimensionPixelSize(R.dimen.screenshot_action_container_offset_y);
- mDismissButtonSize = resources.getDimensionPixelSize(
- R.dimen.screenshot_dismiss_button_tappable_size);
mCornerSizeX = resources.getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
mDismissDeltaY = resources.getDimensionPixelSize(R.dimen.screenshot_dismissal_height_delta);
@@ -318,7 +321,7 @@
Region touchRegion = new Region();
Rect screenshotRect = new Rect();
- mScreenshotView.getBoundsOnScreen(screenshotRect);
+ mScreenshotPreview.getBoundsOnScreen(screenshotRect);
touchRegion.op(screenshotRect, Region.Op.UNION);
Rect actionsRect = new Rect();
mActionsContainer.getBoundsOnScreen(actionsRect);
@@ -469,6 +472,8 @@
*/
private void dismissScreenshot(String reason, boolean immediate) {
Log.v(TAG, "clearing screenshot: " + reason);
+ mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
+ mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
if (!immediate) {
mDismissAnimation = createScreenshotDismissAnimation();
mDismissAnimation.addListener(new AnimatorListenerAdapter() {
@@ -488,23 +493,23 @@
if (mScreenshotLayout.isAttachedToWindow()) {
mWindowManager.removeView(mScreenshotLayout);
}
- mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
- mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
// Clear any references to the bitmap
- mScreenshotView.setImageBitmap(null);
+ mScreenshotPreview.setImageBitmap(null);
+ mScreenshotAnimatedView.setImageBitmap(null);
+ mActionsContainerBackground.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
- mBackgroundView.setVisibility(View.GONE);
mBackgroundProtection.setAlpha(0f);
mDismissButton.setVisibility(View.GONE);
- mScreenshotView.setVisibility(View.GONE);
- mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
- mScreenshotView.setContentDescription(
+ mScreenshotPreview.setVisibility(View.GONE);
+ mScreenshotPreview.setLayerType(View.LAYER_TYPE_NONE, null);
+ mScreenshotPreview.setContentDescription(
mContext.getResources().getString(R.string.screenshot_preview_description));
mScreenshotLayout.setAlpha(1);
mDismissButton.setTranslationY(0);
mActionsContainer.setTranslationY(0);
- mScreenshotView.setTranslationY(0);
+ mActionsContainerBackground.setTranslationY(0);
+ mScreenshotPreview.setTranslationY(0);
}
/**
@@ -514,9 +519,8 @@
*/
private void reloadAssets() {
mDismissImage.setImageDrawable(mContext.getDrawable(R.drawable.screenshot_cancel));
- mActionsContainer.setBackground(
+ mActionsContainerBackground.setBackground(
mContext.getDrawable(R.drawable.action_chip_container_background));
-
}
/**
@@ -558,10 +562,6 @@
Toast.LENGTH_SHORT).show();
}
-
- // Add the view for the animation
- mScreenshotView.setImageBitmap(mScreenBitmap);
-
mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect);
saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
@@ -600,8 +600,8 @@
// Play the shutter sound to notify that we've taken a screenshot
mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
- mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mScreenshotView.buildLayer();
+ mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mScreenshotPreview.buildLayer();
mScreenshotAnimation.start();
});
}
@@ -609,6 +609,14 @@
private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) {
float cornerScale = mCornerSizeX / (float) width;
+ mScreenshotAnimatedView.setScaleX(1);
+ mScreenshotAnimatedView.setScaleY(1);
+ mScreenshotAnimatedView.setX(0);
+ mScreenshotAnimatedView.setY(0);
+
+ mScreenshotAnimatedView.setImageBitmap(mScreenBitmap);
+ mScreenshotPreview.setImageBitmap(mScreenBitmap);
+
AnimatorSet dropInAnimation = new AnimatorSet();
ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
@@ -623,9 +631,16 @@
mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));
final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
- final PointF finalPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f,
- mDisplayMetrics.heightPixels - mScreenshotOffsetYPx
- - height * cornerScale / 2f);
+ float finalX;
+ if (mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_LTR) {
+ finalX = mScreenshotOffsetXPx + width * cornerScale / 2f;
+ } else {
+ finalX = width - mScreenshotOffsetXPx - width * cornerScale / 2f;
+ }
+ float finalY =
+ mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f;
+ final PointF finalPos = new PointF(finalX, finalY);
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
@@ -639,30 +654,33 @@
if (t < scalePct) {
float scale = MathUtils.lerp(
1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct));
- mScreenshotView.setScaleX(scale);
- mScreenshotView.setScaleY(scale);
+ mScreenshotAnimatedView.setScaleX(scale);
+ mScreenshotAnimatedView.setScaleY(scale);
} else {
- mScreenshotView.setScaleX(cornerScale);
- mScreenshotView.setScaleY(cornerScale);
+ mScreenshotAnimatedView.setScaleX(cornerScale);
+ mScreenshotAnimatedView.setScaleY(cornerScale);
}
+ float currentScaleX = mScreenshotAnimatedView.getScaleX();
+ float currentScaleY = mScreenshotAnimatedView.getScaleY();
+
if (t < xPositionPct) {
float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
mFastOutSlowIn.getInterpolation(t / xPositionPct));
- mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f);
+ mScreenshotAnimatedView.setX(xCenter - width * currentScaleX / 2f);
} else {
- mScreenshotView.setX(finalPos.x - width * mScreenshotView.getScaleX() / 2f);
+ mScreenshotAnimatedView.setX(finalPos.x - width * currentScaleX / 2f);
}
float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
mFastOutSlowIn.getInterpolation(t));
- mScreenshotView.setY(yCenter - height * mScreenshotView.getScaleY() / 2f);
+ mScreenshotAnimatedView.setY(yCenter - height * currentScaleY / 2f);
});
toCorner.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
- mScreenshotView.setVisibility(View.VISIBLE);
+ mScreenshotAnimatedView.setVisibility(View.VISIBLE);
}
});
@@ -676,15 +694,16 @@
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mScreenshotView.setScaleX(cornerScale);
- mScreenshotView.setScaleY(cornerScale);
- mScreenshotView.setX(finalPos.x - width * cornerScale / 2f);
- mScreenshotView.setY(finalPos.y - height * cornerScale / 2f);
+ mScreenshotAnimatedView.setScaleX(1);
+ mScreenshotAnimatedView.setScaleY(1);
+ mScreenshotAnimatedView.setX(finalPos.x - width * cornerScale / 2f);
+ mScreenshotAnimatedView.setY(finalPos.y - height * cornerScale / 2f);
Rect bounds = new Rect();
- mScreenshotView.getBoundsOnScreen(bounds);
- mDismissButton.setX(bounds.right - mDismissButtonSize / 2f);
- mDismissButton.setY(bounds.top - mDismissButtonSize / 2f);
+ mDismissButton.getBoundsOnScreen(bounds);
+ mScreenshotAnimatedView.setVisibility(View.GONE);
+ mScreenshotPreview.setVisibility(View.VISIBLE);
mDismissButton.setVisibility(View.VISIBLE);
+ mScreenshotLayout.forceLayout();
}
});
@@ -747,7 +766,7 @@
mActionsView.addView(editChip);
chips.add(editChip);
- mScreenshotView.setOnClickListener(v -> {
+ mScreenshotPreview.setOnClickListener(v -> {
try {
imageData.editAction.actionIntent.send();
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
@@ -757,7 +776,7 @@
Log.e(TAG, "Intent cancelled", e);
}
});
- mScreenshotView.setContentDescription(imageData.editAction.title);
+ mScreenshotPreview.setContentDescription(imageData.editAction.title);
if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) {
ScreenshotActionChip scrollChip = (ScreenshotActionChip) inflater.inflate(
@@ -775,20 +794,33 @@
chips.add(scrollChip);
}
+ // remove the margin from the last chip so that it's correctly aligned with the end
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
+ mActionsView.getChildAt(mActionsView.getChildCount() - 1).getLayoutParams();
+ params.setMarginEnd(0);
+
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS);
float alphaFraction = (float) SCREENSHOT_ACTIONS_ALPHA_DURATION_MS
/ SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS;
- mActionsContainer.setVisibility(VISIBLE);
- mActionsContainer.setAlpha(0);
+ mActionsContainer.setVisibility(View.VISIBLE);
+ mActionsContainer.setAlpha(0f);
+ mActionsContainerBackground.setAlpha(0f);
+ mActionsContainerBackground.setVisibility(View.VISIBLE);
+
+ mActionsContainer.setPivotX(0);
+ mActionsContainerBackground.setPivotX(0);
animator.addUpdateListener(animation -> {
float t = animation.getAnimatedFraction();
mBackgroundProtection.setAlpha(t);
- mActionsContainer.setAlpha(t < alphaFraction ? t / alphaFraction : 1);
+ float containerAlpha = t < alphaFraction ? t / alphaFraction : 1;
+ mActionsContainer.setAlpha(containerAlpha);
+ mActionsContainerBackground.setAlpha(containerAlpha);
float containerScale = SCREENSHOT_ACTIONS_START_SCALE_X
+ (t * (1 - SCREENSHOT_ACTIONS_START_SCALE_X));
mActionsContainer.setScaleX(containerScale);
+ mActionsContainerBackground.setScaleX(containerScale);
for (ScreenshotActionChip chip : chips) {
chip.setAlpha(t);
chip.setScaleX(1 / containerScale); // invert to keep size of children constant
@@ -808,13 +840,14 @@
ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
yAnim.setInterpolator(mAccelerateInterpolator);
yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
- float screenshotStartY = mScreenshotView.getTranslationY();
+ float screenshotStartY = mScreenshotPreview.getTranslationY();
float dismissStartY = mDismissButton.getTranslationY();
yAnim.addUpdateListener(animation -> {
float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
- mScreenshotView.setTranslationY(screenshotStartY + yDelta);
+ mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
mDismissButton.setTranslationY(dismissStartY + yDelta);
mActionsContainer.setTranslationY(yDelta);
+ mActionsContainerBackground.setTranslationY(yDelta);
});
AnimatorSet animSet = new AnimatorSet();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 555202a..e67b3d7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -211,14 +211,16 @@
mTargetShown = imeShouldShow;
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
- } else {
- // Check for an "interruption" of an existing animation. In this case, we need to
- // fake-flip the last-known state direction so that the animation completes in the
- // other direction.
+ } else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
if (mTargetAdjusted != targetAdjusted && targetAdjusted == mAdjusted) {
- if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
- mAdjusted = mTargetAdjusted;
- }
+ // Check for an "interruption" of an existing animation. In this case, we
+ // need to fake-flip the last-known state direction so that the animation
+ // completes in the other direction.
+ mAdjusted = mTargetAdjusted;
+ } else if (targetAdjusted && mTargetAdjusted && mAdjusted) {
+ // Already fully adjusted for IME, but IME height has changed; so, force-start
+ // an async animation to the new IME height.
+ mAdjusted = false;
}
}
if (mPaused) {
@@ -634,6 +636,11 @@
}
}
+ void onSplitDismissed() {
+ mMinimized = false;
+ updateVisibility(false /* visible */);
+ }
+
/** Switch to minimized state if appropriate */
public void setMinimized(final boolean minimized) {
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 2df4506..060760a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
@@ -338,12 +339,12 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
if (mFirstLayout) {
// Wait for first layout so that the ViewRootImpl surface has been created.
initializeSurfaceState();
mFirstLayout = false;
}
- super.onLayout(changed, left, top, right, bottom);
int minimizeLeft = 0;
int minimizeTop = 0;
if (mDockSide == WindowManager.DOCKED_TOP) {
@@ -783,6 +784,20 @@
setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */);
t.apply();
mTiles.releaseTransaction(t);
+
+ // Get the actually-visible bar dimensions (relative to full window). This is a thin
+ // bar going through the center.
+ final Rect dividerBar = isHorizontalDivision()
+ ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(),
+ mDividerInsets + mDividerSize)
+ : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize,
+ mSplitLayout.mDisplayLayout.height());
+ final Region touchRegion = new Region(dividerBar);
+ // Add in the "draggable" portion. While not visible, this is an expanded area that the
+ // user can interact with.
+ touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(),
+ mHandle.getRight(), mHandle.getBottom()));
+ mWindowManager.setTouchRegion(touchRegion);
}
public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 729df38..6ea3132 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -27,6 +27,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import android.graphics.PixelFormat;
+import android.graphics.Region;
import android.os.Binder;
import android.view.View;
import android.view.WindowManager;
@@ -103,4 +104,12 @@
mSystemWindows.updateViewLayout(mView, mLp);
}
}
+
+ /** Sets the touch region to `touchRegion`. Use null to unset.*/
+ public void setTouchRegion(Region touchRegion) {
+ if (mView == null) {
+ return;
+ }
+ mSystemWindows.setTouchableRegion(mView, touchRegion);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 717edc5..2862c83 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -201,7 +201,7 @@
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
WindowManagerProxy.applyDismissSplit(this, true /* dismissOrMaximize */);
- mDivider.updateVisibility(false /* visible */);
+ mDivider.onSplitDismissed();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 8669804..c70d3847 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -38,8 +38,8 @@
@Main private val resources: Resources,
dumpManager: DumpManager
) : Dumpable {
- private val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
- private val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius)
+ val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
+ val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius)
private val blurSupportedSysProp = SystemProperties
.getBoolean("ro.surface_flinger.supports_background_blur", false)
private val blurDisabledSysProp = SystemProperties
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2419515..96d6ecb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -263,7 +263,7 @@
default void showAuthenticationDialog(Bundle bundle,
IBiometricServiceReceiverInternal receiver, int biometricModality,
boolean requireConfirmation, int userId, String opPackageName,
- long operationId) { }
+ long operationId, int sysUiSessionId) { }
default void onBiometricAuthenticated() { }
default void onBiometricHelp(String message) { }
default void onBiometricError(int modality, int error, int vendorCode) { }
@@ -782,7 +782,7 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -792,6 +792,7 @@
args.argi2 = userId;
args.arg4 = opPackageName;
args.arg5 = operationId;
+ args.argi3 = sysUiSessionId;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -1169,7 +1170,8 @@
(boolean) someArgs.arg3 /* requireConfirmation */,
someArgs.argi2 /* userId */,
(String) someArgs.arg4 /* opPackageName */,
- (long) someArgs.arg5 /* operationId */);
+ (long) someArgs.arg5 /* operationId */,
+ someArgs.argi3 /* sysUiSessionId */);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 25f1a97..7aae724 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -20,7 +20,9 @@
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.WallpaperManager
+import android.os.SystemClock
import android.util.Log
+import android.util.MathUtils
import android.view.Choreographer
import android.view.View
import androidx.annotation.VisibleForTesting
@@ -44,6 +46,7 @@
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
+import kotlin.math.sign
/**
* Controller responsible for statusbar window blur.
@@ -61,6 +64,11 @@
) : PanelExpansionListener, Dumpable {
companion object {
private const val WAKE_UP_ANIMATION_ENABLED = true
+ private const val VELOCITY_SCALE = 100f
+ private const val MAX_VELOCITY = 3000f
+ private const val MIN_VELOCITY = -MAX_VELOCITY
+ private const val INTERACTION_BLUR_FRACTION = 0.4f
+ private const val ANIMATION_BLUR_FRACTION = 1f - INTERACTION_BLUR_FRACTION
private const val TAG = "DepthController"
}
@@ -71,8 +79,19 @@
private var updateScheduled: Boolean = false
private var shadeExpansion = 0f
private var ignoreShadeBlurUntilHidden: Boolean = false
+ private var isClosed: Boolean = true
+ private var isOpen: Boolean = false
+ private var isBlurred: Boolean = false
+
+ private var prevTracking: Boolean = false
+ private var prevTimestamp: Long = -1
+ private var prevShadeDirection = 0
+ private var prevShadeVelocity = 0f
+
@VisibleForTesting
var shadeSpring = DepthAnimation()
+ var shadeAnimation = DepthAnimation()
+
@VisibleForTesting
var globalActionsSpring = DepthAnimation()
var showingHomeControls: Boolean = false
@@ -98,12 +117,15 @@
return
}
- if (shadeSpring.radius == 0) {
+ if (shadeSpring.radius == 0 && shadeAnimation.radius == 0) {
return
}
ignoreShadeBlurUntilHidden = true
shadeSpring.animateTo(0)
shadeSpring.finishIfRunning()
+
+ shadeAnimation.animateTo(0)
+ shadeAnimation.finishIfRunning()
}
/**
@@ -132,8 +154,11 @@
@VisibleForTesting
val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false
-
- var shadeRadius = max(shadeSpring.radius, wakeAndUnlockBlurRadius).toFloat()
+ val normalizedBlurRadius = MathUtils.constrain(shadeAnimation.radius,
+ blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
+ val combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
+ normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
+ var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
shadeRadius *= 1f - brightnessMirrorSpring.ratio
val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f
shadeRadius *= (1f - launchProgress) * (1f - launchProgress)
@@ -208,12 +233,15 @@
private val statusBarStateCallback = object : StatusBarStateController.StateListener {
override fun onStateChanged(newState: Int) {
+ updateShadeAnimationBlur(
+ shadeExpansion, prevTracking, prevShadeVelocity, prevShadeDirection)
updateShadeBlur()
}
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
shadeSpring.finishIfRunning()
+ shadeAnimation.finishIfRunning()
globalActionsSpring.finishIfRunning()
brightnessMirrorSpring.finishIfRunning()
}
@@ -234,24 +262,110 @@
// Stop blur effect when scrims is opaque to avoid unnecessary GPU composition.
visibility -> scrimsVisible = visibility == ScrimController.OPAQUE
}
+ shadeAnimation.setStiffness(SpringForce.STIFFNESS_LOW)
+ shadeAnimation.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)
}
/**
* Update blurs when pulling down the shade
*/
override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
- if (expansion == shadeExpansion) {
+ val timestamp = SystemClock.elapsedRealtimeNanos()
+
+ if (shadeExpansion == expansion && prevTracking == tracking) {
+ prevTimestamp = timestamp
return
}
+
+ var deltaTime = 1f
+ if (prevTimestamp < 0) {
+ prevTimestamp = timestamp
+ } else {
+ deltaTime = MathUtils.constrain(
+ ((timestamp - prevTimestamp) / 1E9).toFloat(), 0.00001f, 1f)
+ }
+
+ val diff = expansion - shadeExpansion
+ val shadeDirection = sign(diff).toInt()
+ val shadeVelocity = MathUtils.constrain(
+ VELOCITY_SCALE * diff / deltaTime, MIN_VELOCITY, MAX_VELOCITY)
+ updateShadeAnimationBlur(expansion, tracking, shadeVelocity, shadeDirection)
+
+ prevShadeDirection = shadeDirection
+ prevShadeVelocity = shadeVelocity
shadeExpansion = expansion
+ prevTracking = tracking
+ prevTimestamp = timestamp
+
updateShadeBlur()
}
+ private fun updateShadeAnimationBlur(
+ expansion: Float,
+ tracking: Boolean,
+ velocity: Float,
+ direction: Int
+ ) {
+ if (isOnKeyguardNotDismissing()) {
+ if (expansion > 0f) {
+ // Blur view if user starts animating in the shade.
+ if (isClosed) {
+ animateBlur(true, velocity)
+ isClosed = false
+ }
+
+ // If we were blurring out and the user stopped the animation, blur view.
+ if (tracking && !isBlurred) {
+ animateBlur(true, 0f)
+ }
+
+ // If shade is being closed and the user isn't interacting with it, un-blur.
+ if (!tracking && direction < 0 && isBlurred) {
+ animateBlur(false, velocity)
+ }
+
+ if (expansion == 1f) {
+ if (!isOpen) {
+ isOpen = true
+ // If shade is open and view is not blurred, blur.
+ if (!isBlurred) {
+ animateBlur(true, velocity)
+ }
+ }
+ } else {
+ isOpen = false
+ }
+ // Automatic animation when the user closes the shade.
+ } else if (!isClosed) {
+ isClosed = true
+ // If shade is closed and view is not blurred, blur.
+ if (isBlurred) {
+ animateBlur(false, velocity)
+ }
+ }
+ } else {
+ animateBlur(false, 0f)
+ isClosed = true
+ isOpen = false
+ }
+ }
+
+ private fun animateBlur(blur: Boolean, velocity: Float) {
+ isBlurred = blur
+
+ val targetBlurNormalized = if (blur && isOnKeyguardNotDismissing()) {
+ 1f
+ } else {
+ 0f
+ }
+
+ shadeAnimation.setStartVelocity(velocity)
+ shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized))
+ }
+
private fun updateShadeBlur() {
var newBlur = 0
- val state = statusBarStateController.state
- if ((state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) &&
- !keyguardStateController.isKeyguardFadingAway) {
+ if (isOnKeyguardNotDismissing()) {
newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion)
}
shadeSpring.animateTo(newBlur)
@@ -266,6 +380,12 @@
choreographer.postFrameCallback(updateBlurCallback)
}
+ private fun isOnKeyguardNotDismissing(): Boolean {
+ val state = statusBarStateController.state
+ return (state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) &&
+ !keyguardStateController.isKeyguardFadingAway
+ }
+
fun updateGlobalDialogVisibility(visibility: Float, dialogView: View?) {
globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView)
}
@@ -275,6 +395,7 @@
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
it.println("shadeRadius: ${shadeSpring.radius}")
+ it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
@@ -311,7 +432,7 @@
private var view: View? = null
private var springAnimation = SpringAnimation(this, object :
- FloatPropertyCompat<DepthAnimation>("blurRadius") {
+ FloatPropertyCompat<DepthAnimation>("blurRadius") {
override fun setValue(rect: DepthAnimation?, value: Float) {
radius = value.toInt()
scheduleUpdate(view)
@@ -343,5 +464,17 @@
springAnimation.skipToEnd()
}
}
+
+ fun setStiffness(stiffness: Float) {
+ springAnimation.spring.stiffness = stiffness
+ }
+
+ fun setDampingRatio(dampingRation: Float) {
+ springAnimation.spring.dampingRatio = dampingRation
+ }
+
+ fun setStartVelocity(velocity: Float) {
+ springAnimation.setStartVelocity(velocity)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 8fcc67a..e7f2618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -184,8 +184,11 @@
mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow());
boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());
- boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed()
- || !ent.hasFinishedInitialization();
+ boolean groupChangesAllowed =
+ mVisualStabilityManager.areGroupChangesAllowed() // user isn't looking at notifs
+ || !ent.hasFinishedInitialization() // notif recently added
+ || !mListContainer.containsView(ent.getRow()); // notif recently unfiltered
+
NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
if (!groupChangesAllowed) {
// We don't to change groups while the user is looking at them
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index e81e5ca..2bef355 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -24,6 +24,7 @@
import android.view.animation.Interpolator;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
@@ -69,6 +70,7 @@
};
private final ArrayList<RankedListener> mListeners = new ArrayList<>();
+ private final UiEventLogger mUiEventLogger;
private int mState;
private int mLastState;
private boolean mLeaveOpenOnKeyguardHide;
@@ -119,7 +121,8 @@
private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN;
@Inject
- public StatusBarStateControllerImpl() {
+ public StatusBarStateControllerImpl(UiEventLogger uiEventLogger) {
+ mUiEventLogger = uiEventLogger;
for (int i = 0; i < HISTORY_SIZE; i++) {
mHistoricalRecords[i] = new HistoricalState();
}
@@ -155,6 +158,7 @@
}
mLastState = mState;
mState = state;
+ mUiEventLogger.log(StatusBarStateEvent.fromState(mState));
for (RankedListener rl : new ArrayList<>(mListeners)) {
rl.mListener.onStateChanged(mState);
}
@@ -174,6 +178,11 @@
}
@Override
+ public boolean isPulsing() {
+ return mPulsing;
+ }
+
+ @Override
public float getDozeAmount() {
return mDozeAmount;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
new file mode 100644
index 0000000..8330169
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+/**
+ * Events for changes in the {@link StatusBarState}.
+ */
+public enum StatusBarStateEvent implements UiEventLogger.UiEventEnum {
+
+ @UiEvent(doc = "StatusBarState changed to unknown state")
+ STATUS_BAR_STATE_UNKNOWN(428),
+
+ @UiEvent(doc = "StatusBarState changed to SHADE state")
+ STATUS_BAR_STATE_SHADE(429),
+
+ @UiEvent(doc = "StatusBarState changed to KEYGUARD state")
+ STATUS_BAR_STATE_KEYGUARD(430),
+
+ @UiEvent(doc = "StatusBarState changed to SHADE_LOCKED state")
+ STATUS_BAR_STATE_SHADE_LOCKED(431),
+
+ @UiEvent(doc = "StatusBarState changed to FULLSCREEN_USER_SWITCHER state")
+ STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER(432);
+
+ private int mId;
+ StatusBarStateEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Return the event associated with the state.
+ */
+ public static StatusBarStateEvent fromState(int state) {
+ switch(state) {
+ case StatusBarState.SHADE:
+ return STATUS_BAR_STATE_SHADE;
+ case StatusBarState.KEYGUARD:
+ return STATUS_BAR_STATE_KEYGUARD;
+ case StatusBarState.SHADE_LOCKED:
+ return STATUS_BAR_STATE_SHADE_LOCKED;
+ case StatusBarState.FULLSCREEN_USER_SWITCHER:
+ return STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER;
+ default:
+ return STATUS_BAR_STATE_UNKNOWN;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
index a0b144b..2ab329e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicPrivacyController.java
@@ -54,9 +54,14 @@
}
@Override
+ public void onKeyguardFadingAwayChanged() {
+ onUnlockedChanged();
+ }
+
+ @Override
public void onUnlockedChanged() {
if (isDynamicPrivacyEnabled()) {
- // We only want to notify our listeners if dynamic privacy is actually active
+ // We only want to notify our listeners if dynamic privacy is actually enabled
boolean dynamicallyUnlocked = isDynamicallyUnlocked();
if (dynamicallyUnlocked != mLastDynamicUnlocked || mCacheInvalid) {
mLastDynamicUnlocked = dynamicallyUnlocked;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 55a20fa..040dbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -288,7 +288,7 @@
mContext,
0,
new Intent(Intent.ACTION_VIEW).setData(Uri.parse(helpUrl)),
- 0,
+ PendingIntent.FLAG_IMMUTABLE,
null,
user)
: null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index f1cb783..d251777 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -440,6 +440,10 @@
mLogger.logLifetimeExtended(key, extender.getClass().getName(), "pending");
}
}
+ if (!lifetimeExtended) {
+ // At this point, we are guaranteed the notification will be removed
+ mAllNotifications.remove(pendingEntry);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 9738bcc..c78370e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -27,20 +27,17 @@
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
-
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.PriorityBucket
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
-import java.util.Objects;
+import java.util.Objects
import javax.inject.Inject
-import kotlin.Comparator
private const val TAG = "NotifRankingManager"
@@ -140,33 +137,36 @@
.filterNot(notifFilter::shouldFilterOut)
.sortedWith(rankingComparator)
.toList()
- for (entry in filtered) {
- assignBucketForEntry(entry)
- }
+ assignBuckets(filtered)
return filtered
}
- private fun assignBucketForEntry(entry: NotificationEntry) {
+ private fun assignBuckets(entries: List<NotificationEntry>) {
+ entries.forEach { it.bucket = getBucketForEntry(it) }
+ if (!usePeopleFiltering) {
+ // If we don't have a Conversation section, just assign buckets normally based on the
+ // content.
+ return
+ }
+ // If HUNs are not continuous with the top section, break out into a new Incoming section.
+ entries.asReversed().asSequence().zipWithNext().forEach { (next, entry) ->
+ if (entry.isRowHeadsUp && entry.bucket > next.bucket) {
+ entry.bucket = BUCKET_HEADS_UP
+ }
+ }
+ }
+
+ @PriorityBucket
+ private fun getBucketForEntry(entry: NotificationEntry): Int {
val isHeadsUp = entry.isRowHeadsUp
val isMedia = isImportantMedia(entry)
val isSystemMax = entry.isSystemMax()
- setBucket(entry, isHeadsUp, isMedia, isSystemMax)
- }
-
- private fun setBucket(
- entry: NotificationEntry,
- isHeadsUp: Boolean,
- isMedia: Boolean,
- isSystemMax: Boolean
- ) {
- if (usePeopleFiltering && isHeadsUp) {
- entry.bucket = BUCKET_HEADS_UP
- } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) {
- entry.bucket = BUCKET_PEOPLE
- } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
- entry.bucket = BUCKET_ALERTING
- } else {
- entry.bucket = BUCKET_SILENT
+ return when {
+ usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON ->
+ BUCKET_PEOPLE
+ isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() ->
+ BUCKET_ALERTING
+ else -> BUCKET_SILENT
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
index 1c1b2bb..a0f9dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
@@ -28,10 +28,9 @@
@Singleton
class TargetSdkResolver @Inject constructor(
- private val context: Context,
- private val collection: CommonNotifCollection
+ private val context: Context
) {
- init {
+ fun initialize(collection: CommonNotifCollection) {
collection.addCollectionListener(object : NotifCollectionListener {
override fun onEntryBind(entry: NotificationEntry, sbn: StatusBarNotification) {
entry.targetSdk = resolveNotificationSdk(sbn)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 78ee5f2..f55ce77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -24,8 +24,6 @@
import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -51,6 +49,7 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
+import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
@@ -111,6 +110,7 @@
INotificationManager notificationManager,
LauncherApps launcherApps,
ShortcutManager shortcutManager,
+ ChannelEditorDialogController channelEditorDialogController,
CurrentUserContextTracker contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider) {
return new NotificationGutsManager(
@@ -123,6 +123,7 @@
notificationManager,
launcherApps,
shortcutManager,
+ channelEditorDialogController,
contextTracker,
builderProvider);
}
@@ -161,13 +162,6 @@
return new NotificationPanelLoggerImpl();
}
- /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
- @Singleton
- @Provides
- static UiEventLogger provideUiEventLogger() {
- return new UiEventLoggerImpl();
- }
-
/** Provides an instance of {@link NotificationBlockingHelperManager} */
@Singleton
@Provides
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 c975404..6e4fcd5 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
@@ -25,8 +25,10 @@
import com.android.systemui.statusbar.notification.NotificationClicker
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.NotificationListController
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
+import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
import com.android.systemui.statusbar.notification.interruption.HeadsUpController
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -56,6 +58,8 @@
private val featureFlags: FeatureFlags,
private val notificationListener: NotificationListener,
private val entryManager: NotificationEntryManager,
+ private val notifPipeline: Lazy<NotifPipeline>,
+ private val targetSdkResolver: TargetSdkResolver,
private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
private val notifBindPipelineInitializer: NotifBindPipelineInitializer,
private val deviceProvisionedController: DeviceProvisionedController,
@@ -102,8 +106,10 @@
}
if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ targetSdkResolver.initialize(notifPipeline.get())
// TODO
} else {
+ targetSdkResolver.initialize(entryManager)
remoteInputUriController.attach(entryManager)
groupAlertTransferHelper.bind(entryManager, groupManager)
headsUpManager.addListener(groupManager)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 324bc92..fefad53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -336,6 +336,14 @@
return false;
}
}
+
+ if (entry.hasJustLaunchedFullScreenIntent()) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: recent fullscreen: " + sbn.getKey());
+ }
+ return false;
+ }
+
return true;
}
@@ -365,13 +373,6 @@
return false;
}
- if (entry.hasJustLaunchedFullScreenIntent()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: recent fullscreen: " + sbn.getKey());
- }
- return false;
- }
-
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
index 29447ca..cc917dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
@@ -18,6 +18,7 @@
import android.annotation.MainThread;
import android.util.ArrayMap;
+import android.util.Log;
import androidx.annotation.NonNull;
@@ -66,8 +67,10 @@
public final Params getStageParams(@NonNull NotificationEntry entry) {
Params params = mContentParams.get(entry);
if (params == null) {
- throw new IllegalStateException(
- String.format("Entry does not have any stage parameters. key: %s",
+ // TODO: This should throw an exception but there are some cases of re-entrant calls
+ // in NotificationEntryManager (e.g. b/155324756) that cause removal in update that
+ // lead to inflation after the notification is "removed".
+ Log.wtf(TAG, String.format("Entry does not have any stage parameters. key: %s",
entry.getKey()));
}
return params;
@@ -92,6 +95,8 @@
*/
protected abstract Params newStageParams();
+ private static final String TAG = "BindStage";
+
/**
* Interface for callback.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index e75b705..b163818 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -22,8 +22,8 @@
import android.app.NotificationChannel.DEFAULT_CHANNEL_ID
import android.app.NotificationChannelGroup
import android.app.NotificationManager.IMPORTANCE_NONE
+import android.app.NotificationManager.Importance
import android.content.Context
-import android.content.DialogInterface
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
@@ -37,8 +37,10 @@
import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
import android.widget.TextView
+
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
+
import javax.inject.Inject
import javax.inject.Singleton
@@ -59,11 +61,13 @@
@Singleton
class ChannelEditorDialogController @Inject constructor(
c: Context,
- private val noMan: INotificationManager
+ private val noMan: INotificationManager,
+ private val dialogBuilder: ChannelEditorDialog.Builder
) {
val context: Context = c.applicationContext
- lateinit var dialog: Dialog
+ private var prepared = false
+ private lateinit var dialog: ChannelEditorDialog
private var appIcon: Drawable? = null
private var appUid: Int? = null
@@ -74,13 +78,16 @@
// Caller should set this if they care about when we dismiss
var onFinishListener: OnChannelEditorDialogFinishedListener? = null
- // Channels handed to us from NotificationInfo
@VisibleForTesting
- internal val providedChannels = mutableListOf<NotificationChannel>()
+ internal val paddedChannels = mutableListOf<NotificationChannel>()
+ // Channels handed to us from NotificationInfo
+ private val providedChannels = mutableListOf<NotificationChannel>()
// Map from NotificationChannel to importance
private val edits = mutableMapOf<NotificationChannel, Int>()
- var appNotificationsEnabled = true
+ private var appNotificationsEnabled = true
+ // System settings for app notifications
+ private var appNotificationsCurrentlyEnabled: Boolean? = null
// Keep a mapping of NotificationChannel.getGroup() to the actual group name for display
@VisibleForTesting
@@ -106,10 +113,18 @@
this.appNotificationsEnabled = checkAreAppNotificationsOn()
this.onSettingsClickListener = onSettingsClickListener
+ // These will always start out the same
+ appNotificationsCurrentlyEnabled = appNotificationsEnabled
+
channelGroupList.clear()
channelGroupList.addAll(fetchNotificationChannelGroups())
buildGroupNameLookup()
+ providedChannels.clear()
+ providedChannels.addAll(channels)
padToFourChannels(channels)
+ initDialog()
+
+ prepared = true
}
private fun buildGroupNameLookup() {
@@ -121,21 +136,21 @@
}
private fun padToFourChannels(channels: Set<NotificationChannel>) {
- providedChannels.clear()
+ paddedChannels.clear()
// First, add all of the given channels
- providedChannels.addAll(channels.asSequence().take(4))
+ paddedChannels.addAll(channels.asSequence().take(4))
// Then pad to 4 if we haven't been given that many
- providedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence())
- .filterNot { providedChannels.contains(it) }
+ paddedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence())
+ .filterNot { paddedChannels.contains(it) }
.distinct()
- .take(4 - providedChannels.size))
+ .take(4 - paddedChannels.size))
// If we only got one channel and it has the default miscellaneous tag, then we actually
// are looking at an app with a targetSdk <= O, and it doesn't make much sense to show the
// channel
- if (providedChannels.size == 1 && DEFAULT_CHANNEL_ID == providedChannels[0].id) {
- providedChannels.clear()
+ if (paddedChannels.size == 1 && DEFAULT_CHANNEL_ID == paddedChannels[0].id) {
+ paddedChannels.clear()
}
}
@@ -157,7 +172,9 @@
}
fun show() {
- initDialog()
+ if (!prepared) {
+ throw IllegalStateException("Must call prepareDialogForApp() before calling show()")
+ }
dialog.show()
}
@@ -178,8 +195,10 @@
appUid = null
packageName = null
appName = null
+ appNotificationsCurrentlyEnabled = null
edits.clear()
+ paddedChannels.clear()
providedChannels.clear()
groupNameLookup.clear()
}
@@ -188,12 +207,27 @@
return groupNameLookup[groupId] ?: ""
}
- fun proposeEditForChannel(channel: NotificationChannel, edit: Int) {
+ fun proposeEditForChannel(channel: NotificationChannel, @Importance edit: Int) {
if (channel.importance == edit) {
edits.remove(channel)
} else {
edits[channel] = edit
}
+
+ dialog.updateDoneButtonText(hasChanges())
+ }
+
+ fun proposeSetAppNotificationsEnabled(enabled: Boolean) {
+ appNotificationsEnabled = enabled
+ dialog.updateDoneButtonText(hasChanges())
+ }
+
+ fun areAppNotificationsEnabled(): Boolean {
+ return appNotificationsEnabled
+ }
+
+ private fun hasChanges(): Boolean {
+ return edits.isNotEmpty() || (appNotificationsEnabled != appNotificationsCurrentlyEnabled)
}
@Suppress("unchecked_cast")
@@ -241,7 +275,7 @@
}
}
- if (appNotificationsEnabled != checkAreAppNotificationsOn()) {
+ if (appNotificationsEnabled != appNotificationsCurrentlyEnabled) {
applyAppNotificationsOn(appNotificationsEnabled)
}
}
@@ -252,7 +286,8 @@
}
private fun initDialog() {
- dialog = Dialog(context)
+ dialogBuilder.setContext(context)
+ dialog = dialogBuilder.build()
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
// Prevent a11y readers from reading the first element in the dialog twice
@@ -260,16 +295,21 @@
dialog.apply {
setContentView(R.layout.notif_half_shelf)
setCanceledOnTouchOutside(true)
- setOnDismissListener(object : DialogInterface.OnDismissListener {
- override fun onDismiss(dialog: DialogInterface?) {
- onFinishListener?.onChannelEditorDialogFinished()
- }
- })
- findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply {
+ setOnDismissListener { onFinishListener?.onChannelEditorDialogFinished() }
+
+ val listView = findViewById<ChannelEditorListView>(R.id.half_shelf_container)
+ listView?.apply {
controller = this@ChannelEditorDialogController
appIcon = this@ChannelEditorDialogController.appIcon
appName = this@ChannelEditorDialogController.appName
- channels = providedChannels
+ channels = paddedChannels
+ }
+
+ setOnShowListener {
+ // play a highlight animation for the given channels
+ for (channel in providedChannels) {
+ listView?.highlightChannel(channel)
+ }
}
findViewById<TextView>(R.id.done_button)?.setOnClickListener {
@@ -306,6 +346,28 @@
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
}
+class ChannelEditorDialog(context: Context) : Dialog(context) {
+ fun updateDoneButtonText(hasChanges: Boolean) {
+ findViewById<TextView>(R.id.done_button)?.setText(
+ if (hasChanges)
+ R.string.inline_ok_button
+ else
+ R.string.inline_done_button)
+ }
+
+ class Builder @Inject constructor() {
+ private lateinit var context: Context
+ fun setContext(context: Context): Builder {
+ this.context = context
+ return this
+ }
+
+ fun build(): ChannelEditorDialog {
+ return ChannelEditorDialog(context)
+ }
+ }
+}
+
interface OnChannelEditorDialogFinishedListener {
fun onChannelEditorDialogFinished()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
index 983315e..38a1579 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row
+import android.animation.ArgbEvaluator
+import android.animation.ValueAnimator
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_NONE
@@ -33,8 +35,10 @@
import android.widget.LinearLayout
import android.widget.Switch
import android.widget.TextView
+import com.android.settingslib.Utils
import com.android.systemui.R
+import com.android.systemui.util.Assert
/**
* Half-shelf for notification channel controls
@@ -51,6 +55,7 @@
// The first row is for the entire app
private lateinit var appControlRow: AppControlView
+ private val channelRows = mutableListOf<ChannelRow>()
override fun onFinishInflate() {
super.onFinishInflate()
@@ -58,8 +63,21 @@
appControlRow = findViewById(R.id.app_control)
}
+ /**
+ * Play a highlight animation for the given channel (it really should exist but this will just
+ * fail silently if it doesn't)
+ */
+ fun highlightChannel(channel: NotificationChannel) {
+ Assert.isMainThread()
+ for (row in channelRows) {
+ if (row.channel == channel) {
+ row.playHighlight()
+ }
+ }
+ }
+
private fun updateRows() {
- val enabled = controller.appNotificationsEnabled
+ val enabled = controller.areAppNotificationsEnabled()
val transition = AutoTransition()
transition.duration = 200
@@ -83,13 +101,10 @@
TransitionManager.beginDelayedTransition(this, transition)
// Remove any rows
- val n = childCount
- for (i in n.downTo(0)) {
- val child = getChildAt(i)
- if (child is ChannelRow) {
- removeView(child)
- }
+ for (row in channelRows) {
+ removeView(row)
}
+ channelRows.clear()
updateAppControlRow(enabled)
@@ -105,6 +120,8 @@
val row = inflater.inflate(R.layout.notif_half_shelf_row, null) as ChannelRow
row.controller = controller
row.channel = channel
+
+ channelRows.add(row)
addView(row)
}
@@ -114,7 +131,7 @@
.getString(R.string.notification_channel_dialog_title, appName)
appControlRow.switch.isChecked = enabled
appControlRow.switch.setOnCheckedChangeListener { _, b ->
- controller.appNotificationsEnabled = b
+ controller.proposeSetAppNotificationsEnabled(b)
updateRows()
}
}
@@ -140,8 +157,14 @@
private lateinit var channelName: TextView
private lateinit var channelDescription: TextView
private lateinit var switch: Switch
+ private val highlightColor: Int
var gentle = false
+ init {
+ highlightColor = Utils.getColorAttrDefaultColor(
+ context, android.R.attr.colorControlHighlight)
+ }
+
var channel: NotificationChannel? = null
set(newValue) {
field = newValue
@@ -150,6 +173,7 @@
}
override fun onFinishInflate() {
+ super.onFinishInflate()
channelName = findViewById(R.id.channel_name)
channelDescription = findViewById(R.id.channel_description)
switch = findViewById(R.id.toggle)
@@ -161,6 +185,22 @@
setOnClickListener { switch.toggle() }
}
+ /**
+ * Play an animation that highlights this row
+ */
+ fun playHighlight() {
+ // Use 0 for the start value because our background is given to us by our parent
+ val fadeInLoop = ValueAnimator.ofObject(ArgbEvaluator(), 0, highlightColor)
+ fadeInLoop.duration = 200L
+ fadeInLoop.addUpdateListener { animator ->
+ setBackgroundColor(animator.animatedValue as Int)
+ }
+ fadeInLoop.repeatMode = ValueAnimator.REVERSE
+ // Repeat an odd number of times to we end up normal
+ fadeInLoop.repeatCount = 5
+ fadeInLoop.start()
+ }
+
private fun updateViews() {
val nc = channel ?: return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index f8844c7..f7ad50e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1680,7 +1680,9 @@
public void reset() {
mShowingPublicInitialized = false;
unDismiss();
- resetTranslation();
+ if (mMenuRow == null || !mMenuRow.isMenuVisible()) {
+ resetTranslation();
+ }
onHeightReset();
requestLayout();
}
@@ -1838,10 +1840,6 @@
}
public void resetTranslation() {
- if (mMenuRow != null && mMenuRow.isMenuVisible()) {
- return;
- }
-
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
@@ -2368,6 +2366,11 @@
updateChildrenVisibility();
applyChildrenRoundness();
}
+
+ protected void expandNotification() {
+ mExpandClickListener.onClick(this);
+ }
+
/**
* Returns the number of channels covered by the notification row (including its children if
* it's a summary notification).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index f8d9c46..7a6109d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -130,7 +130,13 @@
mView.setOnDismissRunnable(mOnDismissRunnable);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
- mView.setLongPressListener(mNotificationGutsManager::openGuts);
+ mView.setLongPressListener((v, x, y, item) -> {
+ if (mView.isSummaryWithChildren()) {
+ mView.expandNotification();
+ return true;
+ }
+ return mNotificationGutsManager.openGuts(v, x, y, item);
+ });
}
if (ENABLE_REMOTE_INPUT) {
mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 32477a6..9e70f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -72,6 +72,7 @@
mFacePileProtectionWidth = getResources().getDimensionPixelSize(
R.dimen.conversation_single_line_face_pile_protection_width);
mTransformationHelper.addViewTransformingToSimilar(mConversationIconView);
+ mTransformationHelper.addTransformedView(mConversationSenderName);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
index e4e3ebc..3ee2673 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
@@ -115,6 +115,9 @@
mLogger.logManagedRow(entry.getKey());
final BindEntry bindEntry = getBindEntry(entry);
+ if (bindEntry == null) {
+ return;
+ }
bindEntry.row = row;
if (bindEntry.invalidated) {
requestPipelineRun(entry);
@@ -223,11 +226,6 @@
private @NonNull BindEntry getBindEntry(NotificationEntry entry) {
final BindEntry bindEntry = mBindEntries.get(entry);
- if (bindEntry == null) {
- throw new IllegalStateException(
- String.format("Attempting bind on an inactive notification. key: %s",
- entry.getKey()));
- }
return bindEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 75affdf..3f7c7ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -87,6 +87,7 @@
private final VisualStabilityManager mVisualStabilityManager;
private final AccessibilityManager mAccessibilityManager;
private final HighPriorityProvider mHighPriorityProvider;
+ private final ChannelEditorDialogController mChannelEditorDialogController;
// Dependencies:
private final NotificationLockscreenUserManager mLockscreenUserManager =
@@ -127,6 +128,7 @@
INotificationManager notificationManager,
LauncherApps launcherApps,
ShortcutManager shortcutManager,
+ ChannelEditorDialogController channelEditorDialogController,
CurrentUserContextTracker contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider) {
mContext = context;
@@ -140,6 +142,7 @@
mShortcutManager = shortcutManager;
mContextTracker = contextTracker;
mBuilderProvider = builderProvider;
+ mChannelEditorDialogController = channelEditorDialogController;
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -348,6 +351,7 @@
pmUser,
mNotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
packageName,
row.getEntry().getChannel(),
row.getUniqueChannels(),
@@ -390,6 +394,7 @@
notificationInfoView.bindNotification(
pmUser,
mNotificationManager,
+ mChannelEditorDialogController,
packageName,
row.getEntry().getChannel(),
row.getUniqueChannels(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 12aa4df..08affa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -174,6 +174,7 @@
PackageManager pm,
INotificationManager iNotificationManager,
VisualStabilityManager visualStabilityManager,
+ ChannelEditorDialogController channelEditorDialogController,
String pkg,
NotificationChannel notificationChannel,
Set<NotificationChannel> uniqueChannelsInRow,
@@ -187,7 +188,7 @@
mINotificationManager = iNotificationManager;
mMetricsLogger = Dependency.get(MetricsLogger.class);
mVisualStabilityManager = visualStabilityManager;
- mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
+ mChannelEditorDialogController = channelEditorDialogController;
mPackageName = pkg;
mUniqueChannelsInRow = uniqueChannelsInRow;
mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 2189b87..cc5de65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -17,10 +17,6 @@
package com.android.systemui.statusbar.notification.row;
import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-
-import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -39,10 +35,6 @@
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
-import android.transition.ChangeBounds;
-import android.transition.Fade;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -51,7 +43,6 @@
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -108,6 +99,7 @@
public void bindNotification(
PackageManager pm,
INotificationManager iNotificationManager,
+ ChannelEditorDialogController channelEditorDialogController,
String pkg,
NotificationChannel notificationChannel,
Set<NotificationChannel> uniqueChannelsInRow,
@@ -127,7 +119,7 @@
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mIsNonBlockable = isNonBlockable;
- mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
+ mChannelEditorDialogController = channelEditorDialogController;
mUniqueChannelsInRow = uniqueChannelsInRow;
bindHeader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index d02037c..6eec1ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -109,6 +109,7 @@
@Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
private SectionHeaderView mAlertingHeader;
+ private SectionHeaderView mIncomingHeader;
private PeopleHubView mPeopleHubView;
private boolean mPeopleHubVisible = false;
@@ -199,6 +200,11 @@
mPeopleHubSubscription = mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
}
+ mIncomingHeader = reinflateView(
+ mIncomingHeader, layoutInflater, R.layout.status_bar_notification_section_header);
+ mIncomingHeader.setHeaderText(R.string.notification_section_header_incoming);
+ mIncomingHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
+
if (mMediaControlsView != null) {
mKeyguardMediaPlayer.unbindView();
}
@@ -218,6 +224,7 @@
|| view == mMediaControlsView
|| view == mPeopleHubView
|| view == mAlertingHeader
+ || view == mIncomingHeader
|| !Objects.equals(getBucket(view), getBucket(previous));
}
@@ -229,6 +236,8 @@
private Integer getBucket(View view) {
if (view == mGentleHeader) {
return BUCKET_SILENT;
+ } else if (view == mIncomingHeader) {
+ return BUCKET_HEADS_UP;
} else if (view == mMediaControlsView) {
return BUCKET_MEDIA_CONTROLS;
} else if (view == mPeopleHubView) {
@@ -267,6 +276,8 @@
// Currently, just putting media controls in the front and incrementing the position based
// on the number of heads-up notifs.
int mediaControlsTarget = isKeyguard && usingMediaControls ? 0 : -1;
+ int currentIncomingHeaderIdx = -1;
+ int incomingHeaderTarget = -1;
int currentPeopleHeaderIdx = -1;
int peopleHeaderTarget = -1;
int currentAlertingHeaderIdx = -1;
@@ -281,6 +292,10 @@
View child = mParent.getChildAt(i);
// Track the existing positions of the headers
+ if (child == mIncomingHeader) {
+ currentIncomingHeaderIdx = i;
+ continue;
+ }
if (child == mMediaControlsView) {
currentMediaControlsIdx = i;
continue;
@@ -306,6 +321,26 @@
// Once we enter a new section, calculate the target position for the header.
switch (row.getEntry().getBucket()) {
case BUCKET_HEADS_UP:
+ if (showHeaders && incomingHeaderTarget == -1) {
+ incomingHeaderTarget = i;
+ // Offset the target if there are other headers before this that will be
+ // moved.
+ if (currentIncomingHeaderIdx != -1) {
+ incomingHeaderTarget--;
+ }
+ if (currentMediaControlsIdx != -1) {
+ incomingHeaderTarget--;
+ }
+ if (currentPeopleHeaderIdx != -1) {
+ incomingHeaderTarget--;
+ }
+ if (currentAlertingHeaderIdx != -1) {
+ incomingHeaderTarget--;
+ }
+ if (currentGentleHeaderIdx != -1) {
+ incomingHeaderTarget--;
+ }
+ }
if (mediaControlsTarget != -1) {
mediaControlsTarget++;
}
@@ -378,8 +413,8 @@
alertingHeaderTarget, mAlertingHeader, currentAlertingHeaderIdx);
adjustHeaderVisibilityAndPosition(
peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx);
- adjustViewPosition(
- mediaControlsTarget, mMediaControlsView, currentMediaControlsIdx);
+ adjustViewPosition(mediaControlsTarget, mMediaControlsView, currentMediaControlsIdx);
+ adjustViewPosition(incomingHeaderTarget, mIncomingHeader, currentIncomingHeaderIdx);
// Update headers to reflect state of section contents
mGentleHeader.setAreThereDismissableGentleNotifs(
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 7093dd8..7f32c00 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
@@ -54,6 +54,7 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -756,8 +757,8 @@
boolean showFooterView = (showDismissView || hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
- boolean showHistory = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1;
+ boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
updateFooterView(showFooterView, showDismissView, showHistory);
}
@@ -5730,8 +5731,8 @@
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
view.setOnClickListener(v -> {
- final boolean showHistory = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) == 1;
+ final boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
Intent intent = showHistory ? new Intent(
Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(
Settings.ACTION_NOTIFICATION_SETTINGS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 0680c7f..7951541 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -15,16 +15,19 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
-import android.provider.Settings.Secure;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -32,18 +35,24 @@
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
+import java.util.ArrayList;
+import java.util.Objects;
+
import javax.inject.Inject;
/**
* Manages which tiles should be automatically added to QS.
*/
public class AutoTileManager {
+ private static final String TAG = "AutoTileManager";
+
public static final String HOTSPOT = "hotspot";
public static final String SAVER = "saver";
public static final String INVERSION = "inversion";
public static final String WORK = "work";
public static final String NIGHT = "night";
public static final String CAST = "cast";
+ public static final String SETTING_SEPARATOR = ":";
private final Context mContext;
private final QSTileHost mHost;
@@ -54,6 +63,7 @@
private final ManagedProfileController mManagedProfileController;
private final NightDisplayListener mNightDisplayListener;
private final CastController mCastController;
+ private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
@Inject
public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
@@ -78,21 +88,6 @@
if (!mAutoTracker.isAdded(SAVER)) {
dataSaverController.addCallback(mDataSaverListener);
}
- if (!mAutoTracker.isAdded(INVERSION)) {
- mColorsSetting = new SecureSetting(mContext, mHandler,
- Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
- @Override
- protected void handleValueChanged(int value, boolean observedChange) {
- if (mAutoTracker.isAdded(INVERSION)) return;
- if (value != 0) {
- mHost.addTile(INVERSION);
- mAutoTracker.setTileAdded(INVERSION);
- mHandler.post(() -> mColorsSetting.setListening(false));
- }
- }
- };
- mColorsSetting.setListening(true);
- }
if (!mAutoTracker.isAdded(WORK)) {
managedProfileController.addCallback(mProfileCallback);
}
@@ -103,12 +98,10 @@
if (!mAutoTracker.isAdded(CAST)) {
castController.addCallback(mCastCallback);
}
+ populateSettingsList();
}
public void destroy() {
- if (mColorsSetting != null) {
- mColorsSetting.setListening(false);
- }
mAutoTracker.destroy();
mHotspotController.removeCallback(mHotspotCallback);
mDataSaverController.removeCallback(mDataSaverListener);
@@ -117,6 +110,42 @@
mNightDisplayListener.setCallback(null);
}
mCastController.removeCallback(mCastCallback);
+ int settingsN = mAutoAddSettingList.size();
+ for (int i = 0; i < settingsN; i++) {
+ mAutoAddSettingList.get(i).setListening(false);
+ }
+ }
+
+ /**
+ * Populates a list with the pairs setting:spec in the config resource.
+ * <p>
+ * This will only create {@link AutoAddSetting} objects for those tiles that have not been
+ * auto-added before, and set the corresponding {@link ContentObserver} to listening.
+ */
+ private void populateSettingsList() {
+ String [] autoAddList;
+ try {
+ autoAddList = mContext.getResources().getStringArray(
+ R.array.config_quickSettingsAutoAdd);
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "Missing config resource");
+ return;
+ }
+ // getStringArray returns @NotNull, so if we got here, autoAddList is not null
+ for (String tile : autoAddList) {
+ String[] split = tile.split(SETTING_SEPARATOR);
+ if (split.length == 2) {
+ String setting = split[0];
+ String spec = split[1];
+ if (!mAutoTracker.isAdded(spec)) {
+ AutoAddSetting s = new AutoAddSetting(mContext, mHandler, setting, spec);
+ mAutoAddSettingList.add(s);
+ s.setListening(true);
+ }
+ } else {
+ Log.w(TAG, "Malformed item in array: " + tile);
+ }
+ }
}
public void unmarkTileAsAutoAdded(String tabSpec) {
@@ -139,8 +168,6 @@
}
};
- private SecureSetting mColorsSetting;
-
private final DataSaverController.Listener mDataSaverListener = new Listener() {
@Override
public void onDataSaverChanged(boolean isDataSaving) {
@@ -213,4 +240,47 @@
}
}
};
+
+ @VisibleForTesting
+ protected SecureSetting getSecureSettingForKey(String key) {
+ for (SecureSetting s : mAutoAddSettingList) {
+ if (Objects.equals(key, s.getKey())) {
+ return s;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Tracks tiles that should be auto added when a setting changes.
+ * <p>
+ * When the setting changes to a value different from 0, if the tile has not been auto added
+ * before, it will be added and the listener will be stopped.
+ */
+ private class AutoAddSetting extends SecureSetting {
+ private final String mSpec;
+
+ AutoAddSetting(Context context, Handler handler, String setting, String tileSpec) {
+ super(context, handler, setting);
+ mSpec = tileSpec;
+ }
+
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ if (mAutoTracker.isAdded(mSpec)) {
+ // This should not be listening anymore
+ mHandler.post(() -> setListening(false));
+ return;
+ }
+ if (value != 0) {
+ if (mSpec.startsWith(CustomTile.PREFIX)) {
+ mHost.addTile(CustomTile.getComponentFromSpec(mSpec));
+ } else {
+ mHost.addTile(mSpec);
+ }
+ mAutoTracker.setTileAdded(mSpec);
+ mHandler.post(() -> setListening(false));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 9bf14e4..4afeba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -214,7 +214,6 @@
dozing = false;
}
-
mStatusBarStateController.setIsDozing(dozing);
}
@@ -260,7 +259,6 @@
mKeyguardViewMediator.setPulsing(pulsing);
mNotificationPanel.setPulsing(pulsing);
mVisualStabilityManager.setPulsing(pulsing);
- mLockscreenLockIconController.setPulsing(pulsing);
mIgnoreTouchWhilePulsing = false;
if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) {
mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index ba8a634..0e8c1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -34,8 +34,11 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.ISystemGestureExclusionListener;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -50,6 +53,7 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -144,9 +148,9 @@
// The right side edge width where touch down is allowed
private int mEdgeWidthRight;
// The bottom gesture area height
- private int mBottomGestureHeight;
+ private float mBottomGestureHeight;
// The slop to distinguish between horizontal and vertical motion
- private final float mTouchSlop;
+ private float mTouchSlop;
// Duration after which we consider the event as longpress.
private final int mLongPressTimeout;
private int mStartingQuickstepRotation = -1;
@@ -211,10 +215,6 @@
mPluginManager = pluginManager;
Dependency.get(ProtoTracer.class).add(this);
- // Reduce the default touch slop to ensure that we can intercept the gesture
- // before the app starts to react to it.
- // TODO(b/130352502) Tune this value and extract into a constant
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 0.75f;
mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
ViewConfiguration.getLongPressTimeout());
@@ -233,8 +233,21 @@
mIsBackGestureAllowed =
!mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
- mBottomGestureHeight = res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_gesture_height);
+ final DisplayMetrics dm = res.getDisplayMetrics();
+ final float defaultGestureHeight = res.getDimension(
+ com.android.internal.R.dimen.navigation_bar_gesture_height) / dm.density;
+ final float gestureHeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.BACK_GESTURE_BOTTOM_HEIGHT,
+ defaultGestureHeight);
+ mBottomGestureHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gestureHeight,
+ dm);
+
+ // Reduce the default touch slop to ensure that we can intercept the gesture
+ // before the app starts to react to it.
+ // TODO(b/130352502) Tune this value and extract into a constant
+ final float backGestureSlop = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.BACK_GESTURE_SLOP_MULTIPLIER, 0.75f);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop() * backGestureSlop;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 092dd49..5b7ffd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -97,6 +97,7 @@
public void restoreState(Bundle savedInstanceState) {
setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0));
+ mNextDarkIntensity = mDarkIntensity;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index a2e7306..8a5c8b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -76,8 +76,6 @@
private boolean mKeyguardShowing;
private boolean mKeyguardJustShown;
private boolean mBlockUpdates;
- private boolean mPulsing;
- private boolean mDozing;
private boolean mSimLocked;
private boolean mTransientBiometricsError;
private boolean mDocked;
@@ -124,6 +122,11 @@
}
@Override
+ public void onPulsingChanged(boolean pulsing) {
+ setPulsing(pulsing);
+ }
+
+ @Override
public void onDozeAmountChanged(float linear, float eased) {
if (mLockIcon != null) {
mLockIcon.setDozeAmount(eased);
@@ -378,8 +381,7 @@
/**
* Propagate {@link StatusBar} pulsing state.
*/
- public void setPulsing(boolean pulsing) {
- mPulsing = pulsing;
+ private void setPulsing(boolean pulsing) {
update();
}
@@ -461,7 +463,8 @@
shouldUpdate = false;
}
if (shouldUpdate && mLockIcon != null) {
- mLockIcon.update(state, mPulsing, mDozing, mKeyguardJustShown);
+ mLockIcon.update(state, mStatusBarStateController.isPulsing(),
+ mStatusBarStateController.isDozing(), mKeyguardJustShown);
}
mLastState = state;
mKeyguardJustShown = false;
@@ -477,7 +480,8 @@
return STATE_LOCK_OPEN;
} else if (mTransientBiometricsError) {
return STATE_BIOMETRICS_ERROR;
- } else if (mKeyguardUpdateMonitor.isFaceDetectionRunning() && !mPulsing) {
+ } else if (mKeyguardUpdateMonitor.isFaceDetectionRunning()
+ && !mStatusBarStateController.isPulsing()) {
return STATE_SCANNING_FACE;
} else {
return STATE_LOCKED;
@@ -489,7 +493,6 @@
}
private void setDozing(boolean isDozing) {
- mDozing = isDozing;
update();
}
@@ -504,7 +507,8 @@
* @return true if the visibility changed
*/
private boolean updateIconVisibility() {
- boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
+ boolean onAodNotPulsingOrDocked = mStatusBarStateController.isDozing()
+ && (!mStatusBarStateController.isPulsing() || mDocked);
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|| mShowingLaunchAffordance;
if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 6061b1e..06b7d1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -39,6 +39,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -71,20 +72,38 @@
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "ACTION_OVERLAY_CHANGED");
- }
- updateCurrentInteractionMode(true /* notify */);
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_OVERLAY_CHANGED");
+ }
+ updateCurrentInteractionMode(true /* notify */);
}
};
+ private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback =
+ new DeviceProvisionedController.DeviceProvisionedListener() {
+ @Override
+ public void onUserSwitched() {
+ if (DEBUG) {
+ Log.d(TAG, "onUserSwitched: "
+ + ActivityManagerWrapper.getInstance().getCurrentUserId());
+ }
+
+ // Update the nav mode for the current user
+ updateCurrentInteractionMode(true /* notify */);
+ }
+ };
+
+
@Inject
- public NavigationModeController(Context context, @UiBackground Executor uiBgExecutor) {
+ public NavigationModeController(Context context,
+ DeviceProvisionedController deviceProvisionedController,
+ @UiBackground Executor uiBgExecutor) {
mContext = context;
mCurrentUserContext = context;
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
mUiBgExecutor = uiBgExecutor;
+ deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
overlayFilter.addDataScheme("package");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 462b42a..567ddb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -273,8 +273,7 @@
private void applyFocusableFlag(State state) {
boolean panelFocusable = state.mNotificationShadeFocusable && state.mPanelExpanded;
if (state.mBouncerShowing && (state.mKeyguardOccluded || state.mKeyguardNeedsInput)
- || ENABLE_REMOTE_INPUT && state.mRemoteInputActive
- || state.mBubbleExpanded) {
+ || ENABLE_REMOTE_INPUT && state.mRemoteInputActive) {
mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
@@ -320,9 +319,10 @@
private boolean isExpanded(State state) {
return !state.mForceCollapsed && (state.isKeyguardShowingAndNotOccluded()
|| state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
- || state.mHeadsUpShowing || state.mBubblesShowing
+ || state.mHeadsUpShowing
|| state.mScrimsVisibility != ScrimController.TRANSPARENT)
- || state.mBackgroundBlurRadius > 0;
+ || state.mBackgroundBlurRadius > 0
+ || state.mLaunchingActivity;
}
private void applyFitsSystemWindows(State state) {
@@ -486,6 +486,11 @@
apply(mCurrentState);
}
+ void setLaunchingActivity(boolean launching) {
+ mCurrentState.mLaunchingActivity = launching;
+ apply(mCurrentState);
+ }
+
public void setScrimsVisibility(int scrimsVisibility) {
mCurrentState.mScrimsVisibility = scrimsVisibility;
apply(mCurrentState);
@@ -579,36 +584,6 @@
}
/**
- * Sets whether there are bubbles showing on the screen.
- */
- public void setBubblesShowing(boolean bubblesShowing) {
- mCurrentState.mBubblesShowing = bubblesShowing;
- apply(mCurrentState);
- }
-
- /**
- * The bubbles showing state for the status bar.
- */
- public boolean getBubblesShowing() {
- return mCurrentState.mBubblesShowing;
- }
-
- /**
- * Sets if there is a bubble being expanded on the screen.
- */
- public void setBubbleExpanded(boolean bubbleExpanded) {
- mCurrentState.mBubbleExpanded = bubbleExpanded;
- apply(mCurrentState);
- }
-
- /**
- * Whether the bubble is shown in expanded state for the status bar.
- */
- public boolean getBubbleExpanded() {
- return mCurrentState.mBubbleExpanded;
- }
-
- /**
* Whether the status bar panel is expanded or not.
*/
public boolean getPanelExpanded() {
@@ -676,11 +651,10 @@
boolean mForceCollapsed;
boolean mForceDozeBrightness;
boolean mForceUserActivity;
+ boolean mLaunchingActivity;
boolean mBackdropShowing;
boolean mWallpaperSupportsAmbientMode;
boolean mNotTouchable;
- boolean mBubblesShowing;
- boolean mBubbleExpanded;
boolean mForceHasTopUi;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 596a607..0d25898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -93,6 +93,7 @@
private PhoneStatusBarView mStatusBarView;
private PhoneStatusBarTransitions mBarTransitions;
private StatusBar mService;
+ private NotificationShadeWindowController mNotificationShadeWindowController;
private DragDownHelper mDragDownHelper;
private boolean mDoubleTapEnabled;
private boolean mSingleTapEnabled;
@@ -430,10 +431,14 @@
public void setExpandAnimationPending(boolean pending) {
mExpandAnimationPending = pending;
+ mNotificationShadeWindowController
+ .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
}
public void setExpandAnimationRunning(boolean running) {
mExpandAnimationRunning = running;
+ mNotificationShadeWindowController
+ .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
}
public void cancelExpandHelper() {
@@ -456,8 +461,9 @@
}
}
- public void setService(StatusBar statusBar) {
+ public void setService(StatusBar statusBar, NotificationShadeWindowController controller) {
mService = statusBar;
+ mNotificationShadeWindowController = controller;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 977a307..7c41bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -125,6 +125,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ updateResources();
// May trigger cutout space layout-ing
if (updateOrientationAndCutout()) {
@@ -298,6 +299,24 @@
ViewGroup.LayoutParams layoutParams = getLayoutParams();
mStatusBarHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_height);
layoutParams.height = mStatusBarHeight - waterfallTopInset;
+
+ int statusBarPaddingTop = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_padding_top);
+ int statusBarPaddingStart = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_padding_start);
+ int statusBarPaddingEnd = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_padding_end);
+
+ View sbContents = findViewById(R.id.status_bar_contents);
+ sbContents.setPaddingRelative(
+ statusBarPaddingStart,
+ statusBarPaddingTop,
+ statusBarPaddingEnd,
+ 0);
+
+ findViewById(R.id.notification_lights_out)
+ .setPaddingRelative(0, statusBarPaddingStart, 0, 0);
+
setLayoutParams(layoutParams);
}
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 c590139..33997b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -440,24 +440,7 @@
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
- applyExpansionToAlpha();
- if (mUpdatePending) {
- return;
- }
- setOrAdaptCurrentAnimation(mScrimBehind);
- setOrAdaptCurrentAnimation(mScrimInFront);
- setOrAdaptCurrentAnimation(mScrimForBubble);
- dispatchScrimState(mScrimBehind.getViewAlpha());
-
- // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
- // and docking.
- if (mWallpaperVisibilityTimedOut) {
- mWallpaperVisibilityTimedOut = false;
- DejankUtils.postAfterTraversal(() -> {
- mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
- AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
- });
- }
+ applyAndDispatchExpansion();
}
}
@@ -513,6 +496,27 @@
}
}
+ private void applyAndDispatchExpansion() {
+ applyExpansionToAlpha();
+ if (mUpdatePending) {
+ return;
+ }
+ setOrAdaptCurrentAnimation(mScrimBehind);
+ setOrAdaptCurrentAnimation(mScrimInFront);
+ setOrAdaptCurrentAnimation(mScrimForBubble);
+ dispatchScrimState(mScrimBehind.getViewAlpha());
+
+ // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
+ // and docking.
+ if (mWallpaperVisibilityTimedOut) {
+ mWallpaperVisibilityTimedOut = false;
+ DejankUtils.postAfterTraversal(() -> {
+ mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
+ AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ });
+ }
+ }
+
/**
* Sets the given drawable as the background of the scrim that shows up behind the
* notifications.
@@ -1006,6 +1010,9 @@
public void setExpansionAffectsAlpha(boolean expansionAffectsAlpha) {
mExpansionAffectsAlpha = expansionAffectsAlpha;
+ if (expansionAffectsAlpha) {
+ applyAndDispatchExpansion();
+ }
}
public void setKeyguardOccluded(boolean keyguardOccluded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ac5557b..dd54a3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1001,7 +1001,7 @@
updateTheme();
inflateStatusBarWindow();
- mNotificationShadeWindowViewController.setService(this);
+ mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController);
mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
@@ -1144,7 +1144,7 @@
ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
- ScrimView scrimForBubble = mNotificationShadeWindowView.findViewById(R.id.scrim_for_bubble);
+ ScrimView scrimForBubble = mBubbleController.getScrimForBubble();
mScrimController.setScrimVisibleListener(scrimsVisible -> {
mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index d40b5f9..44ece35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -285,18 +285,7 @@
mLogger.logHandleClickAfterKeyguardDismissed(sbn.getKey());
// TODO: Some of this code may be able to move to NotificationEntryManager.
- if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(sbn.getKey())) {
- // Release the HUN notification to the shade.
-
- if (mPresenter.isPresenterFullyCollapsed()) {
- HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
- }
- //
- // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
- // become canceled shortly by NoMan, but we can't assume that.
- mHeadsUpManager.removeNotification(sbn.getKey(),
- true /* releaseImmediately */);
- }
+ removeHUN(row);
NotificationEntry parentToCancel = null;
if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
NotificationEntry summarySbn = mGroupManager.getLogicalGroupSummary(sbn);
@@ -461,8 +450,12 @@
row, mStatusBar.isOccluded())),
new UserHandle(UserHandle.getUserId(appUid)));
mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
+
+ // Putting it back on the main thread, since we're touching views
+ mMainThreadHandler.post(() -> {
+ removeHUN(row);
+ });
if (shouldCollapse()) {
- // Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
}
@@ -483,7 +476,7 @@
if (showHistory) {
tsb.addNextIntent(intent);
}
- tsb.startActivities();
+ tsb.startActivities(null, UserHandle.CURRENT);
if (shouldCollapse()) {
// Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
@@ -494,6 +487,20 @@
}, null, false /* afterKeyguardGone */);
}
+ private void removeHUN(ExpandableNotificationRow row) {
+ String key = row.getEntry().getSbn().getKey();
+ if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
+ // Release the HUN notification to the shade.
+ if (mPresenter.isPresenterFullyCollapsed()) {
+ HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
+ }
+
+ // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
+ // become canceled shortly by NoMan, but we can't assume that.
+ mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);
+ }
+ }
+
private void handleFullScreenIntent(NotificationEntry entry) {
if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 5bab867..9c7f490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -32,7 +32,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.ScreenDecorations;
-import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -45,8 +44,8 @@
/**
* Manages what parts of the status bar are touchable. Clients are primarily UI that display in the
- * status bar even though the UI doesn't look like part of the status bar. Currently this
- * includes HeadsUpNotifications and Bubbles.
+ * status bar even though the UI doesn't look like part of the status bar. Currently this consists
+ * of HeadsUpNotifications.
*/
@Singleton
public final class StatusBarTouchableRegionManager implements Dumpable {
@@ -55,7 +54,6 @@
private final Context mContext;
private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final BubbleController mBubbleController;
private boolean mIsStatusBarExpanded = false;
private boolean mShouldAdjustInsets = false;
@@ -73,8 +71,7 @@
Context context,
NotificationShadeWindowController notificationShadeWindowController,
ConfigurationController configurationController,
- HeadsUpManagerPhone headsUpManager,
- BubbleController bubbleController
+ HeadsUpManagerPhone headsUpManager
) {
mContext = context;
initResources();
@@ -117,11 +114,6 @@
mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> {
updateTouchableRegion();
});
-
- mBubbleController = bubbleController;
- mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
- updateTouchableRegion();
- });
}
protected void setup(
@@ -172,12 +164,6 @@
mStatusBarHeight);
updateRegionForNotch(mTouchableRegion);
}
-
- // Update touchable region for bubbles
- Rect bubbleRect = mBubbleController.getTouchableRegion();
- if (bubbleRect != null) {
- mTouchableRegion.union(bubbleRect);
- }
return mTouchableRegion;
}
@@ -198,7 +184,6 @@
&& (mNotificationShadeWindowView.getRootWindowInsets().getDisplayCutout() != null);
boolean shouldObserve = mHeadsUpManager.hasPinnedHeadsUp()
|| mHeadsUpManager.isHeadsUpGoingAway()
- || mBubbleController.hasBubbles()
|| mForceCollapsedUntilLayout
|| hasCutoutInset
|| mNotificationShadeWindowController.getForcePluginOpen();
@@ -266,7 +251,7 @@
}
// Update touch insets to include any area needed for touching features that live in
- // the status bar (ie: heads up notifications or bubbles)
+ // the status bar (ie: heads up notifications)
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(calculateTouchableRegion());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index a81189e..b9168e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,11 @@
boolean isAodPowerSave();
/**
+ * Initializes the class.
+ */
+ default void init() { }
+
+ /**
* Returns {@code true} if reverse is supported.
*/
default boolean isReverseSupported() { return false; }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 95b41a1..00419e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -80,7 +80,7 @@
@VisibleForTesting
@Inject
- protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+ public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
@Main Handler mainHandler, @Background Handler bgHandler) {
mContext = context;
@@ -89,10 +89,6 @@
mPowerManager = powerManager;
mEstimates = enhancedEstimates;
mBroadcastDispatcher = broadcastDispatcher;
-
- registerReceiver();
- updatePowerSave();
- updateEstimate();
}
private void registerReceiver() {
@@ -104,6 +100,13 @@
}
@Override
+ public void init() {
+ registerReceiver();
+ updatePowerSave();
+ updateEstimate();
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BatteryController state:");
pw.print(" mLevel="); pw.println(mLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 45e47f1..f8da03a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -46,6 +46,8 @@
private static final String TAG = "KeyguardUserSwitcher";
private static final boolean ALWAYS_ON = false;
+ private static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
+ private static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
private final Container mUserSwitcherContainer;
private final KeyguardStatusBarView mStatusBarView;
@@ -293,6 +295,9 @@
mCurrentUserView = convertView;
}
convertView.setTag(item);
+ convertView.setAlpha(
+ item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA
+ : USER_SWITCH_DISABLED_ALPHA);
return convertView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index bb0b5e0..412962c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -48,6 +48,7 @@
import android.widget.BaseAdapter;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -61,6 +62,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -108,13 +110,15 @@
private int mSecondaryUser = UserHandle.USER_NULL;
private Intent mSecondaryUserServiceIntent;
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
+ private final UiEventLogger mUiEventLogger;
@Inject
public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
@Main Handler handler, ActivityStarter activityStarter,
- BroadcastDispatcher broadcastDispatcher) {
+ BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mUiEventLogger = uiEventLogger;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
}
@@ -801,7 +805,7 @@
UserDetailView v;
if (!(convertView instanceof UserDetailView)) {
v = UserDetailView.inflate(context, parent, false);
- v.createAndSetAdapter(UserSwitcherController.this);
+ v.createAndSetAdapter(UserSwitcherController.this, mUiEventLogger);
} else {
v = (UserDetailView) convertView;
}
@@ -827,6 +831,21 @@
public int getMetricsCategory() {
return MetricsEvent.QS_USERDETAIL;
}
+
+ @Override
+ public UiEventLogger.UiEventEnum openDetailEvent() {
+ return QSUserSwitcherEvent.QS_USER_DETAIL_OPEN;
+ }
+
+ @Override
+ public UiEventLogger.UiEventEnum closeDetailEvent() {
+ return QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE;
+ }
+
+ @Override
+ public UiEventLogger.UiEventEnum moreSettingsEvent() {
+ return QSUserSwitcherEvent.QS_USER_MORE_SETTINGS;
+ }
};
private final KeyguardStateController.Callback mCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 5f82118..6a9d9b6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -126,10 +126,11 @@
/**
* Allow the media player to be shown in the QS area, controlled by 2 flags.
- * On by default, but can be disabled by setting to 0
+ * Off by default, but can be disabled by setting to 0
*/
public static boolean useQsMediaPlayer(Context context) {
- int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 1);
+ int flag = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0);
return flag > 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 8acfbf2..7729965 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -23,6 +23,7 @@
import android.os.Process;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -50,6 +51,17 @@
return thread.getLooper();
}
+ /** Long running tasks Looper */
+ @Provides
+ @Singleton
+ @LongRunning
+ public static Looper provideLongRunningLooper() {
+ HandlerThread thread = new HandlerThread("SysUiLng",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ return thread.getLooper();
+ }
+
/** Main Looper */
@Provides
@Main
@@ -89,6 +101,16 @@
}
/**
+ * Provide a Long running Executor by default.
+ */
+ @Provides
+ @Singleton
+ @LongRunning
+ public static Executor provideLongRunningExecutor(@LongRunning Looper looper) {
+ return new ExecutorImpl(looper);
+ }
+
+ /**
* Provide a Background-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 7bb987c..0cd4fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -56,9 +56,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.qs.QSDndEvent;
+import com.android.systemui.qs.QSEvents;
import com.android.systemui.statusbar.policy.ZenModeController;
import java.io.FileDescriptor;
@@ -103,6 +106,7 @@
private final TransitionHelper mTransitionHelper = new TransitionHelper();
private final Uri mForeverId;
private final ConfigurableTexts mConfigurableTexts;
+ private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
@@ -662,6 +666,7 @@
tag.rb.setChecked(true);
if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
+ mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT);
select(tag.condition);
announceConditionSelection(tag);
}
@@ -767,6 +772,7 @@
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
+ mUiEventLogger.log(up ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index c22b718f..c7e9acc 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -21,6 +21,7 @@
import android.animation.ValueAnimator;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;
@@ -188,7 +189,16 @@
if (mInsetsState.equals(insetsState)) {
return;
}
+
+ final InsetsSource newSource = insetsState.getSource(InsetsState.ITYPE_IME);
+ final Rect newFrame = newSource.getFrame();
+ final Rect oldFrame = mInsetsState.getSource(InsetsState.ITYPE_IME).getFrame();
+
mInsetsState.set(insetsState, true /* copySources */);
+ if (mImeShowing && !newFrame.equals(oldFrame) && newSource.isVisible()) {
+ if (DEBUG) Slog.d(TAG, "insetsChanged when IME showing, restart animation");
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 0b6e4b2..93f45c5 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -23,7 +23,9 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.MergedConfiguration;
@@ -139,6 +141,23 @@
}
/**
+ * Sets the touchable region of a view's window. This will be cropped to the window size.
+ * @param view
+ * @param region
+ */
+ public void setTouchableRegion(@NonNull View view, Region region) {
+ SurfaceControlViewHost root = mViewRoots.get(view);
+ if (root == null) {
+ return;
+ }
+ WindowlessWindowManager wwm = root.getWindowlessWM();
+ if (!(wwm instanceof SysUiWindowManager)) {
+ return;
+ }
+ ((SysUiWindowManager) wwm).setTouchableRegionForWindow(view, region);
+ }
+
+ /**
* Adds a root for system-ui window management with no views. Only useful for IME.
*/
public void addRoot(int displayId, int windowType) {
@@ -170,8 +189,8 @@
public SurfaceControl getViewSurface(View rootView) {
for (int i = 0; i < mPerDisplay.size(); ++i) {
for (int iWm = 0; iWm < mPerDisplay.valueAt(i).mWwms.size(); ++iWm) {
- SurfaceControl out =
- mPerDisplay.valueAt(i).mWwms.get(iWm).getSurfaceControlForWindow(rootView);
+ SurfaceControl out = mPerDisplay.valueAt(i).mWwms.valueAt(iWm)
+ .getSurfaceControlForWindow(rootView);
if (out != null) {
return out;
}
@@ -289,6 +308,14 @@
SurfaceControl getSurfaceControlForWindow(View rootView) {
return getSurfaceControl(rootView);
}
+
+ void setTouchableRegionForWindow(View rootView, Region region) {
+ IBinder token = rootView.getWindowToken();
+ if (token == null) {
+ return;
+ }
+ setTouchRegion(token, region);
+ }
}
class ContainerWindow extends IWindow.Stub {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index fc1ddf7..821b850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -470,7 +470,8 @@
true /* requireConfirmation */,
0 /* userId */,
"testPackage",
- 0 /* operationId */);
+ 0 /* operationId */,
+ 0 /* sysUiSessionId */);
}
private Bundle createTestDialogBundle(int authenticators) {
@@ -508,7 +509,7 @@
@Override
protected AuthDialog buildDialog(Bundle biometricPromptBundle,
boolean requireConfirmation, int userId, int type, String opPackageName,
- boolean skipIntro, long operationId) {
+ boolean skipIntro, long operationId, int sysUiSessionId) {
mLastBiometricPromptBundle = biometricPromptBundle;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index c2b3506..e2f303e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -30,7 +30,6 @@
import static org.junit.Assert.assertNull;
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.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -141,6 +140,8 @@
private KeyguardBypassController mKeyguardBypassController;
@Mock
private FloatingContentCoordinator mFloatingContentCoordinator;
+ @Mock
+ private BubbleDataRepository mDataRepository;
private SysUiState mSysUiState;
private boolean mSysUiStateBubblesExpanded;
@@ -162,8 +163,6 @@
private ExpandableNotificationRow mNonBubbleNotifRow;
@Mock
- private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
- @Mock
private BubbleController.BubbleExpandListener mBubbleExpandListener;
@Mock
private PendingIntent mDeleteIntent;
@@ -278,9 +277,9 @@
mFeatureFlagsOldPipeline,
mDumpManager,
mFloatingContentCoordinator,
+ mDataRepository,
mSysUiState,
mock(INotificationManager.class));
- mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
// Get a reference to the BubbleController's entry listener
@@ -298,7 +297,6 @@
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -316,14 +314,11 @@
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotificationEntryManager).updateNotifications(any());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
- assertFalse(mNotificationShadeWindowController.getBubblesShowing());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -388,7 +383,6 @@
assertTrue(mBubbleController.hasBubbles());
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
- assertFalse(mNotificationShadeWindowController.getBubblesShowing());
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -408,14 +402,12 @@
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
- assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
// Expand the stack
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
- assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
assertTrue(mSysUiStateBubblesExpanded);
@@ -427,7 +419,6 @@
mBubbleController.collapseStack();
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
assertFalse(mBubbleController.isStackExpanded());
- assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -553,7 +544,6 @@
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -588,7 +578,6 @@
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
assertFalse(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
@@ -609,9 +598,6 @@
mRow.getEntry().getKey());
assertFalse(mBubbleController.isStackExpanded());
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -629,9 +615,6 @@
mRow.getEntry().getKey());
assertTrue(mBubbleController.isStackExpanded());
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
assertTrue(mSysUiStateBubblesExpanded);
}
@@ -651,9 +634,6 @@
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -679,9 +659,6 @@
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-
assertFalse(mSysUiStateBubblesExpanded);
}
@@ -716,7 +693,6 @@
mEntryListener.onPendingEntryAdded(mNonBubbleNotifRow.getEntry());
mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
- verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
assertThat(mBubbleController.hasBubbles()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 23dfb7c..8a83b84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -26,7 +26,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -136,6 +135,8 @@
@Mock
private FloatingContentCoordinator mFloatingContentCoordinator;
@Mock
+ private BubbleDataRepository mDataRepository;
+ @Mock
private NotificationShadeWindowView mNotificationShadeWindowView;
private SysUiState mSysUiState = new SysUiState();
@@ -150,8 +151,6 @@
private ExpandableNotificationRow mRow2;
private ExpandableNotificationRow mNonBubbleNotifRow;
@Mock
- private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
- @Mock
private BubbleController.BubbleExpandListener mBubbleExpandListener;
@Mock
private PendingIntent mDeleteIntent;
@@ -253,10 +252,10 @@
mFeatureFlagsNewPipeline,
mDumpManager,
mFloatingContentCoordinator,
+ mDataRepository,
mSysUiState,
mock(INotificationManager.class));
mBubbleController.addNotifCallback(mNotifCallback);
- mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
// Get a reference to the BubbleController's entry listener
@@ -269,8 +268,6 @@
public void testAddBubble() {
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
-
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
}
@Test
@@ -286,13 +283,10 @@
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
- assertFalse(mNotificationShadeWindowController.getBubblesShowing());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
}
@Test
@@ -347,7 +341,6 @@
assertTrue(mBubbleController.hasBubbles());
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
- assertFalse(mNotificationShadeWindowController.getBubblesShowing());
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
@@ -365,14 +358,12 @@
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
- assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
// Expand the stack
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
- assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
// Make sure the notif is suppressed
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
@@ -381,7 +372,6 @@
mBubbleController.collapseStack();
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
assertFalse(mBubbleController.isStackExpanded());
- assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
}
@Test
@@ -495,7 +485,6 @@
mEntryListener.onEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
// Expand
BubbleStackView stackView = mBubbleController.getStackView();
@@ -528,7 +517,6 @@
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
- verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
assertFalse(mBubbleController.hasBubbles());
}
@@ -546,9 +534,6 @@
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
mRow.getEntry().getKey());
assertFalse(mBubbleController.isStackExpanded());
-
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
@Test
@@ -564,9 +549,6 @@
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
mRow.getEntry().getKey());
assertTrue(mBubbleController.isStackExpanded());
-
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
@Test
@@ -584,9 +566,6 @@
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
-
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
@Test
@@ -610,9 +589,6 @@
// Dot + flyout is hidden because notif is suppressed
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
-
- // # of bubbles should change
- verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
}
@Test
@@ -630,7 +606,6 @@
mEntryListener.onEntryAdded(mNonBubbleNotifRow.getEntry());
mEntryListener.onEntryUpdated(mNonBubbleNotifRow.getEntry());
- verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
assertThat(mBubbleController.hasBubbles()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index 7815ae7..1542b86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -55,14 +55,15 @@
FeatureFlags featureFlags,
DumpManager dumpManager,
FloatingContentCoordinator floatingContentCoordinator,
+ BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
zenModeController, lockscreenUserManager, groupManager, entryManager,
- notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
- notificationManager);
+ notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
+ dataRepository, sysUiState, notificationManager);
setInflateSynchronously(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
index 5b78067..ae73879 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
@@ -27,6 +27,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
@@ -65,7 +66,8 @@
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private DockManager mDockManager = new DockManagerFake();
- private StatusBarStateController mStatusBarStateController = new StatusBarStateControllerImpl();
+ private StatusBarStateController mStatusBarStateController =
+ new StatusBarStateControllerImpl(new UiEventLoggerFake());
@Before
public void setup() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
index 8b5cc9a..b9cb499 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
@@ -25,6 +25,7 @@
import android.testing.TestableLooper;
import android.util.DisplayMetrics;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
@@ -67,7 +68,7 @@
FalsingDataProvider falsingDataProvider = new FalsingDataProvider(dm);
DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake();
DockManager dockManager = new DockManagerFake();
- mStatusBarStateController = new StatusBarStateControllerImpl();
+ mStatusBarStateController = new StatusBarStateControllerImpl(new UiEventLoggerFake());
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
mFalsingManager = new BrightLineFalsingManager(falsingDataProvider,
mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 13a7708..9b40c5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -38,10 +38,12 @@
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -104,6 +106,21 @@
}
@Test
+ fun testImmediateListingReload_doesNotCrash() {
+ val exec = Executor { it.run() }
+ val mockServiceListing = mock(ServiceListing::class.java)
+ var callback: ServiceListing.Callback? = null
+ `when`(mockServiceListing.addCallback(any<ServiceListing.Callback>())).then {
+ callback = it.getArgument(0)
+ Unit
+ }
+ `when`(mockServiceListing.reload()).then {
+ callback?.onServicesReloaded(listOf(serviceInfo))
+ }
+ ControlsListingControllerImpl(mContext, exec, { mockServiceListing })
+ }
+
+ @Test
fun testStartsOnUser() {
assertEquals(user, controller.currentUserId)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 28a3d6a..cde575d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -362,28 +362,21 @@
@Test
fun taskUpdatesProgress() {
- // GIVEN that the PlaybackState contins the current position
- val position = 200L
+ // GIVEN that the PlaybackState contins the initial position
+ val initialPosition = 0L
val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, position, 1f)
+ setState(PlaybackState.STATE_PLAYING, initialPosition, 1f)
build()
}
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController, Color.RED)
- // AND the playback state advances
- val nextPosition = 300L
- val nextState = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, nextPosition, 1f)
- build()
- }
- whenever(mockController.getPlaybackState()).thenReturn(nextState)
// WHEN the task runs
with(fakeExecutor) {
advanceClockToNext()
runAllReady()
}
- // THEN elapsed time is captured
- assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(nextPosition.toInt())
+ // THEN elapsed time has increased
+ assertThat(viewModel.progress.value!!.elapsedTime).isGreaterThan(initialPosition.toInt())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index 8879e83..353efee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -16,6 +16,7 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
@@ -33,11 +34,13 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,10 +57,13 @@
private ActivityStarter mActivityStarter;
private DetailAdapter mMockDetailAdapter;
private TestableLooper mTestableLooper;
+ private UiEventLoggerFake mUiEventLogger;
@Before
public void setup() throws Exception {
mTestableLooper = TestableLooper.get(this);
+ mUiEventLogger = QSEvents.INSTANCE.setLoggerForTesting();
+
mTestableLooper.runWithLooper(() -> {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
@@ -70,6 +76,19 @@
when(mMockDetailAdapter.createDetailView(any(), any(), any()))
.thenReturn(mock(View.class));
});
+
+ // Only detail in use is the user detail
+ when(mMockDetailAdapter.openDetailEvent())
+ .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN);
+ when(mMockDetailAdapter.closeDetailEvent())
+ .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE);
+ when(mMockDetailAdapter.moreSettingsEvent())
+ .thenReturn(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS);
+ }
+
+ @After
+ public void tearDown() {
+ QSEvents.INSTANCE.resetLogger();
}
@Test
@@ -79,9 +98,16 @@
mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
verify(mMetricsLogger).visible(eq(mMockDetailAdapter.getMetricsCategory()));
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN.getId(), mUiEventLogger.eventId(0));
+ mUiEventLogger.getLogs().clear();
+
mQsDetail.handleShowingDetail(null, 0, 0, false);
verify(mMetricsLogger).hidden(eq(mMockDetailAdapter.getMetricsCategory()));
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE.getId(), mUiEventLogger.eventId(0));
+
ViewUtils.detachView(mQsDetail);
mTestableLooper.processAllMessages();
}
@@ -92,10 +118,13 @@
mTestableLooper.processAllMessages();
mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
- mQsDetail.findViewById(android.R.id.button2).performClick();
+ mUiEventLogger.getLogs().clear();
+ mQsDetail.requireViewById(android.R.id.button2).performClick();
int metricsCategory = mMockDetailAdapter.getMetricsCategory();
verify(mMetricsLogger).action(eq(ACTION_QS_MORE_SETTINGS), eq(metricsCategory));
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS.getId(), mUiEventLogger.eventId(0));
verify(mActivityStarter).postStartActivityDismissingKeyguard(any(), anyInt());
@@ -105,7 +134,9 @@
@Test
public void testNullAdapterClick() {
- mQsDetail.setupDetailFooter(mock(DetailAdapter.class));
- mQsDetail.findViewById(android.R.id.button2).performClick();
+ DetailAdapter mock = mock(DetailAdapter.class);
+ when(mock.moreSettingsEvent()).thenReturn(DetailAdapter.INVALID);
+ mQsDetail.setupDetailFooter(mock);
+ mQsDetail.requireViewById(android.R.id.button2).performClick();
}
}
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 1f494a6..d338cbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -34,6 +34,7 @@
import androidx.test.filters.Suppress;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.CarrierText;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -106,7 +107,7 @@
mock(PluginManager.class), mock(TunerService.class),
() -> mock(AutoTileManager.class), mock(DumpManager.class),
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
- mock(QSLogger.class));
+ mock(QSLogger.class), mock(UiEventLogger.class));
qs.setHost(host);
qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index 392adf9..128d6e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -25,6 +25,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -35,7 +37,9 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
@@ -45,6 +49,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import org.junit.Before;
@@ -94,17 +99,25 @@
private ActivityStarter mActivityStarter;
@Mock
private NotificationEntryManager mEntryManager;
+ private UiEventLoggerFake mUiEventLogger;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
-
mTestableLooper = TestableLooper.get(this);
+
+ // Dependencies for QSSecurityFooter
+ mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
+ mDependency.injectMockDependency(SecurityController.class);
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class));
+
+ mUiEventLogger = new UiEventLoggerFake();
mTestableLooper.runWithLooper(() -> {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
mQSLogger, mForegroundExecutor, mBackgroundExecutor,
- mLocalBluetoothManager, mActivityStarter, mEntryManager);
+ mLocalBluetoothManager, mActivityStarter, mEntryManager, mUiEventLogger);
// Provides a parent with non-zero size for QSPanel
mParentView = new FrameLayout(mContext);
mParentView.addView(mQsPanel);
@@ -124,9 +137,17 @@
mQsPanel.setExpanded(true);
verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true));
verify(mQSLogger).logPanelExpanded(true, mQsPanel.getDumpableTag());
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(QSEvent.QS_PANEL_EXPANDED.getId(), mUiEventLogger.eventId(0));
+ mUiEventLogger.getLogs().clear();
+
mQsPanel.setExpanded(false);
verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false));
verify(mQSLogger).logPanelExpanded(false, mQsPanel.getDumpableTag());
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(QSEvent.QS_PANEL_COLLAPSED.getId(), mUiEventLogger.eventId(0));
+ mUiEventLogger.getLogs().clear();
+
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 95c3e5a..1147739 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -41,6 +41,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.CollectionUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -50,7 +51,6 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.phone.AutoTileManager;
@@ -105,6 +105,8 @@
private QSLogger mQSLogger;
@Mock
private CustomTile mCustomTile;
+ @Mock
+ private UiEventLogger mUiEventLogger;
private Handler mHandler;
private TestableLooper mLooper;
@@ -117,14 +119,9 @@
mHandler = new Handler(mLooper.getLooper());
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
- mBroadcastDispatcher, mStatusBar, mQSLogger);
+ mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger);
setUpTileFactory();
- // Override this config so there are no unexpected tiles
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.string.config_defaultExtraQuickSettingsTiles,
- "");
-
Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
"", ActivityManager.getCurrentUser());
}
@@ -208,34 +205,6 @@
}
@Test
- public void testDefaultAndExtra() {
- mContext.getOrCreateTestableResources()
- .addOverride(R.string.quick_settings_tiles_default, "spec1");
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.string.config_defaultExtraQuickSettingsTiles, "spec2");
- mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default");
- assertEquals(2, mQSTileHost.getTiles().size());
- QSTile[] elements = mQSTileHost.getTiles().toArray(new QSTile[0]);
- assertTrue(elements[0] instanceof TestTile1);
- assertTrue(elements[1] instanceof TestTile2);
-
- verify(mQSLogger).logTileAdded("spec1");
- verify(mQSLogger).logTileAdded("spec2");
- }
-
- @Test
- public void testExtraCustom() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.string.config_defaultExtraQuickSettingsTiles,
- CUSTOM_TILE_SPEC);
- mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default");
- assertEquals(1, mQSTileHost.getTiles().size());
- assertEquals(mCustomTile, CollectionUtils.firstOrNull(mQSTileHost.getTiles()));
-
- verify(mQSLogger).logTileAdded(CUSTOM_TILE_SPEC);
- }
-
- @Test
public void testNoRepeatedSpecs_addTile() {
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
@@ -298,10 +267,11 @@
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
PluginManager pluginManager, TunerService tunerService,
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
- BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger) {
+ BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
+ UiEventLogger uiEventLogger) {
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
tunerService, autoTiles, dumpManager, broadcastDispatcher,
- Optional.of(statusBar), qsLogger);
+ Optional.of(statusBar), qsLogger, uiEventLogger);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 25bac7a..204de929 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -24,6 +24,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.QSTileHost;
@@ -42,7 +43,8 @@
@Before
public void setup() throws Exception {
- TestableLooper.get(this).runWithLooper(() -> mTileAdapter = new TileAdapter(mContext));
+ TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
+ new TileAdapter(mContext, new UiEventLoggerFake()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 72a6503..53ef866 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -23,10 +23,10 @@
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -41,6 +41,7 @@
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -50,10 +51,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -63,6 +60,7 @@
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -73,6 +71,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class TileQueryHelperTest extends SysuiTestCase {
private static final String CURRENT_TILES = "wifi,dnd,nfc";
private static final String ONLY_STOCK_TILES = "wifi,dnd";
@@ -99,8 +98,6 @@
private QSTileHost mQSTileHost;
@Mock
private PackageManager mPackageManager;
- @Mock
- private QSLogger mQSLogger;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -112,8 +109,8 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
mContext.setMockPackageManager(mPackageManager);
- when(mQSTileHost.getQSLogger()).thenReturn(mQSLogger);
mState = new QSTile.State();
doAnswer(invocation -> {
@@ -279,11 +276,10 @@
}
@Test
- public void testQueryTiles_notAvailableDestroyed_isNotNullSpec() {
- HotspotController mockHC = mock(HotspotController.class);
- DataSaverController mockDSC = mock(DataSaverController.class);
- when(mockHC.isHotspotSupported()).thenReturn(false);
- HotspotTile t = new HotspotTile(mQSTileHost, mockHC, mockDSC);
+ public void testQueryTiles_notAvailableDestroyed_tileSpecIsSet() {
+ Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
+
+ QSTile t = mock(QSTile.class);
when(mQSTileHost.createTile("hotspot")).thenReturn(t);
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
@@ -292,6 +288,8 @@
mTileQueryHelper.queryTiles(mQSTileHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
- verify(mQSLogger).logTileDestroyed(eq("hotspot"), anyString());
+ InOrder verifier = inOrder(t);
+ verifier.verify(t).setTileSpec("hotspot");
+ verifier.verify(t).destroy();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 884e4c0..2fc3d72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -30,6 +30,7 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
@@ -81,6 +82,8 @@
private StatusBar mStatusBar;
@Mock
private QSLogger mQSLogger;
+ @Mock
+ private UiEventLogger mUiEventLogger;
@Before
public void setUp() throws Exception {
@@ -98,7 +101,8 @@
mDumpManager,
mBroadcastDispatcher,
Optional.of(mStatusBar),
- mQSLogger);
+ mQSLogger,
+ mUiEventLogger);
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 4fada33..1c0d451 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -46,12 +46,16 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSEvent;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
@@ -83,6 +87,8 @@
private QSTileHost mHost;
private MetricsLogger mMetricsLogger;
private StatusBarStateController mStatusBarStateController;
+ private UiEventLoggerFake mUiEventLoggerFake;
+ private InstanceId mInstanceId = InstanceId.fakeInstanceId(5);
@Captor
private ArgumentCaptor<LogMaker> mLogCaptor;
@@ -94,12 +100,15 @@
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mDependency.injectMockDependency(ActivityStarter.class);
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mUiEventLoggerFake = new UiEventLoggerFake();
mStatusBarStateController =
mDependency.injectMockDependency(StatusBarStateController.class);
mHost = mock(QSTileHost.class);
when(mHost.indexOf(SPEC)).thenReturn(POSITION);
when(mHost.getContext()).thenReturn(mContext.getBaseContext());
when(mHost.getQSLogger()).thenReturn(mQsLogger);
+ when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake);
+ when(mHost.getNewInstanceId()).thenReturn(mInstanceId);
mTile = spy(new TileImpl(mHost));
mTile.mHandler = mTile.new H(mTestableLooper.getLooper());
@@ -110,6 +119,9 @@
public void testClick_Metrics() {
mTile.click();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_CLICK)));
+ assertEquals(1, mUiEventLoggerFake.numLogs());
+ UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0);
+ assertEvent(QSEvent.QS_ACTION_CLICK, event);
}
@Test
@@ -133,6 +145,9 @@
public void testSecondaryClick_Metrics() {
mTile.secondaryClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
+ assertEquals(1, mUiEventLoggerFake.numLogs());
+ UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0);
+ assertEvent(QSEvent.QS_ACTION_SECONDARY_CLICK, event);
}
@Test
@@ -156,6 +171,9 @@
public void testLongClick_Metrics() {
mTile.longClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS)));
+ assertEquals(1, mUiEventLoggerFake.numLogs());
+ UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0);
+ assertEvent(QSEvent.QS_ACTION_LONG_PRESS, event);
}
@@ -249,6 +267,13 @@
verify(mQsLogger).logTileChangeListening(SPEC, false);
}
+ private void assertEvent(UiEventLogger.UiEventEnum eventType,
+ UiEventLoggerFake.FakeUiEvent fakeEvent) {
+ assertEquals(eventType.getId(), fakeEvent.eventId);
+ assertEquals(SPEC, fakeEvent.packageName);
+ assertEquals(mInstanceId, fakeEvent.instanceId);
+ }
+
private class TileLogMatcher implements ArgumentMatcher<LogMaker> {
private final int mCategory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index b51e716..6d6a4d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -24,8 +24,11 @@
import android.view.View
import android.view.ViewGroup
import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.statusbar.policy.UserSwitcherController
+import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -50,15 +53,17 @@
@Mock private lateinit var mPicture: Bitmap
@Mock private lateinit var mLayoutInflater: LayoutInflater
private lateinit var adapter: UserDetailView.Adapter
+ private lateinit var uiEventLogger: UiEventLoggerFake
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ uiEventLogger = UiEventLoggerFake()
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater)
`when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
.thenReturn(mInflatedUserDetailItemView)
- adapter = UserDetailView.Adapter(mContext, mUserSwitcherController)
+ adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger)
}
private fun clickableTest(
@@ -77,6 +82,17 @@
}
@Test
+ fun testUserSwitchLog() {
+ val user = createUserRecord(false /* current */, false /* guest */)
+ val v = adapter.createUserDetailItemView(View(mContext), mParent, user)
+ `when`(v.tag).thenReturn(user)
+ adapter.onClick(v)
+
+ assertEquals(1, uiEventLogger.numLogs())
+ assertEquals(QSUserSwitcherEvent.QS_USER_SWITCH.id, uiEventLogger.eventId(0))
+ }
+
+ @Test
fun testGuestIsClickable_differentViews_notCurrent() {
clickableTest(false, true, mOtherView, true)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index cffcabb..63e6e8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -410,11 +410,12 @@
Bundle bundle = new Bundle();
String packageName = "test";
final long operationId = 1;
+ final int sysUiSessionId = 2;
mCommandQueue.showAuthenticationDialog(bundle, null /* receiver */, 1, true, 3,
- packageName, operationId);
+ packageName, operationId, sysUiSessionId);
waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3),
- eq(packageName), eq(operationId));
+ eq(packageName), eq(operationId), eq(sysUiSessionId));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index c874915..c46ac47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -64,6 +64,7 @@
@Mock private lateinit var root: View
@Mock private lateinit var viewRootImpl: ViewRootImpl
@Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
+ @Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@@ -80,11 +81,15 @@
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
(answer.arguments[0] as Float * maxBlur).toInt()
}
+ `when`(blurUtils.minBlurRadius).thenReturn(0)
+ `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
+
notificationShadeDepthController = NotificationShadeDepthController(
statusBarStateController, blurUtils, biometricUnlockController,
keyguardStateController, choreographer, wallpaperManager,
notificationShadeWindowController, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
+ notificationShadeDepthController.shadeAnimation = shadeAnimation
notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root
@@ -104,16 +109,61 @@
notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
false /* tracking */)
verify(shadeSpring).animateTo(eq(maxBlur), any())
+ verify(shadeAnimation).animateTo(eq(maxBlur), any())
+ }
+
+ @Test
+ fun onPanelExpansionChanged_animatesBlurIn_ifShade() {
+ notificationShadeDepthController.onPanelExpansionChanged(0.01f /* expansion */,
+ false /* tracking */)
+ verify(shadeAnimation).animateTo(eq(maxBlur), any())
+ }
+
+ @Test
+ fun onPanelExpansionChanged_animatesBlurOut_ifShade() {
+ onPanelExpansionChanged_animatesBlurIn_ifShade()
+ clearInvocations(shadeAnimation)
+ notificationShadeDepthController.onPanelExpansionChanged(0f /* expansion */,
+ false /* tracking */)
+ verify(shadeAnimation).animateTo(eq(0), any())
+ }
+
+ @Test
+ fun onPanelExpansionChanged_animatesBlurOut_ifFlick() {
+ onPanelExpansionChanged_apliesBlur_ifShade()
+ clearInvocations(shadeAnimation)
+ notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
+ true /* tracking */)
+ verify(shadeAnimation, never()).animateTo(anyInt(), any())
+
+ notificationShadeDepthController.onPanelExpansionChanged(0.9f /* expansion */,
+ true /* tracking */)
+ verify(shadeAnimation, never()).animateTo(anyInt(), any())
+
+ notificationShadeDepthController.onPanelExpansionChanged(0.8f /* expansion */,
+ false /* tracking */)
+ verify(shadeAnimation).animateTo(eq(0), any())
+ }
+
+ @Test
+ fun onPanelExpansionChanged_animatesBlurIn_ifFlickCancelled() {
+ onPanelExpansionChanged_animatesBlurOut_ifFlick()
+ clearInvocations(shadeAnimation)
+ notificationShadeDepthController.onPanelExpansionChanged(0.6f /* expansion */,
+ true /* tracking */)
+ verify(shadeAnimation).animateTo(eq(maxBlur), any())
}
@Test
fun onStateChanged_reevalutesBlurs_ifSameRadiusAndNewState() {
onPanelExpansionChanged_apliesBlur_ifShade()
clearInvocations(shadeSpring)
+ clearInvocations(shadeAnimation)
statusBarState = StatusBarState.KEYGUARD
statusBarStateListener.onStateChanged(statusBarState)
verify(shadeSpring).animateTo(eq(0), any())
+ verify(shadeAnimation).animateTo(eq(0), any())
}
@Test
@@ -147,6 +197,7 @@
@Test
fun updateBlurCallback_setsBlur_whenExpanded() {
`when`(shadeSpring.radius).thenReturn(maxBlur)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur))
}
@@ -154,6 +205,7 @@
@Test
fun updateBlurCallback_appLaunchAnimation_overridesZoom() {
`when`(shadeSpring.radius).thenReturn(maxBlur)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur)
val animProgress = ActivityLaunchAnimator.ExpandAnimationParameters()
animProgress.linearProgress = 1f
notificationShadeDepthController.notificationLaunchAnimationParams = animProgress
@@ -187,6 +239,7 @@
`when`(brightnessSpring.ratio).thenReturn(1f)
// And shade is blurred
`when`(shadeSpring.radius).thenReturn(maxBlur)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(notificationShadeWindowController).setBackgroundBlurRadius(0)
@@ -207,8 +260,10 @@
val animProgress = ActivityLaunchAnimator.ExpandAnimationParameters()
animProgress.linearProgress = 0.5f
`when`(shadeSpring.radius).thenReturn(0)
+ `when`(shadeAnimation.radius).thenReturn(0)
notificationShadeDepthController.notificationLaunchAnimationParams = animProgress
verify(shadeSpring, never()).animateTo(anyInt(), any())
+ verify(shadeAnimation, never()).animateTo(anyInt(), any())
}
private fun <T : Any> safeEq(value: T): T {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
new file mode 100644
index 0000000..fca6bc5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+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)
+@TestableLooper.RunWithLooper
+class StatusBarStateControllerImplTest : SysuiTestCase() {
+
+ private lateinit var controller: StatusBarStateControllerImpl
+ private lateinit var uiEventLogger: UiEventLoggerFake
+
+ @Before
+ fun setUp() {
+ uiEventLogger = UiEventLoggerFake()
+ controller = StatusBarStateControllerImpl(uiEventLogger)
+ }
+
+ @Test
+ fun testChangeState_logged() {
+ TestableLooper.get(this).runWithLooper {
+ controller.state = StatusBarState.FULLSCREEN_USER_SWITCHER
+ controller.state = StatusBarState.KEYGUARD
+ controller.state = StatusBarState.SHADE
+ controller.state = StatusBarState.SHADE_LOCKED
+ }
+
+ val logs = uiEventLogger.logs
+ assertEquals(4, logs.size)
+ val ids = logs.map(UiEventLoggerFake.FakeUiEvent::eventId)
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER.id, ids[0])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[1])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[2])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[3])
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
new file mode 100644
index 0000000..b5b2f1f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class StatusBarStateEventTest : SysuiTestCase() {
+
+ @Test
+ fun testFromState() {
+ val events = listOf(
+ StatusBarStateEvent.STATUS_BAR_STATE_SHADE,
+ StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED,
+ StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD,
+ StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER,
+ StatusBarStateEvent.STATUS_BAR_STATE_UNKNOWN
+ )
+ val states = listOf(
+ StatusBarState.SHADE,
+ StatusBarState.SHADE_LOCKED,
+ StatusBarState.KEYGUARD,
+ StatusBarState.FULLSCREEN_USER_SWITCHER,
+ -1
+ )
+ events.zip(states).forEach { (event, state) ->
+ assertEquals(event, StatusBarStateEvent.fromState(state))
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 99dc895..68cf66d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -19,6 +19,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -85,6 +86,22 @@
verify(mListener).onDynamicPrivacyChanged();
}
+ @Test
+ public void testNotifiedWhenKeyguardFadingAwayChanges() {
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
+ enableDynamicPrivacy();
+
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+ mDynamicPrivacyController.onKeyguardFadingAwayChanged();
+ verify(mListener).onDynamicPrivacyChanged();
+ reset(mListener);
+
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(false);
+ mDynamicPrivacyController.onUnlockedChanged();
+ verify(mListener).onDynamicPrivacyChanged();
+ }
+
private void enableDynamicPrivacy() {
when(mLockScreenUserManager.shouldHideNotifications(any())).thenReturn(
false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 972357e..bb7f73a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -26,6 +26,7 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -93,6 +94,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -261,6 +263,19 @@
}
@Test
+ public void testRemoveUninflatedNotification_removesNotificationFromAllNotifsList() {
+ // GIVEN an uninflated entry is added
+ mEntryManager.addNotification(mSbn, mRankingMap);
+ assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
+
+ // WHEN the uninflated entry is removed
+ mEntryManager.performRemoveNotification(mSbn, UNDEFINED_DISMISS_REASON);
+
+ // THEN the entry is still removed from the allNotifications list
+ assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
+ }
+
+ @Test
public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -545,6 +560,15 @@
/* End annex */
+ private boolean entriesContainKey(Collection<NotificationEntry> entries, String key) {
+ for (NotificationEntry entry : entries) {
+ if (entry.getSbn().getKey().equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private Notification.Action createAction() {
return new Notification.Action.Builder(
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
index 8b81a7a..64d0256 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
@@ -36,12 +36,14 @@
import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
+import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -59,11 +61,16 @@
@Mock
private lateinit var mockNoMan: INotificationManager
+ @Mock(answer = Answers.RETURNS_SELF)
+ private lateinit var dialogBuilder: ChannelEditorDialog.Builder
+ @Mock
+ private lateinit var dialog: ChannelEditorDialog
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- controller = ChannelEditorDialogController(mContext, mockNoMan)
+ `when`(dialogBuilder.build()).thenReturn(dialog)
+ controller = ChannelEditorDialogController(mContext, mockNoMan, dialogBuilder)
channel1 = NotificationChannel(TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT)
channel2 = NotificationChannel(TEST_CHANNEL2, TEST_CHANNEL_NAME2, IMPORTANCE_DEFAULT)
@@ -86,7 +93,7 @@
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
- assertEquals(2, controller.providedChannels.size)
+ assertEquals(2, controller.paddedChannels.size)
}
@Test
@@ -97,7 +104,7 @@
setOf(channelDefault), appIcon, clickListener)
assertEquals("No channels should be shown when there is only the miscellaneous channel",
- 0, controller.providedChannels.size)
+ 0, controller.paddedChannels.size)
}
@Test
@@ -119,7 +126,7 @@
setOf(channel1), appIcon, clickListener)
assertEquals("ChannelEditorDialog should fetch enough channels to show 4",
- 4, controller.providedChannels.size)
+ 4, controller.paddedChannels.size)
}
@Test
@@ -147,7 +154,7 @@
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
- controller.appNotificationsEnabled = false
+ controller.proposeSetAppNotificationsEnabled(false)
controller.apply()
verify(mockNoMan, times(1)).setNotificationsEnabledForPackage(
@@ -162,7 +169,7 @@
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
- controller.appNotificationsEnabled = true
+ controller.proposeSetAppNotificationsEnabled(true)
controller.apply()
verify(mockNoMan, times(1)).setNotificationsEnabledForPackage(
@@ -171,12 +178,52 @@
@Test
fun testSettingsClickListenerNull_noCrash() {
+ // GIVEN editor dialog
group.channels = listOf(channel1, channel2)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, null)
+ // WHEN user taps settings
// Pass in any old view, it should never actually be used
controller.launchSettings(View(context))
+
+ // THEN no crash
+ }
+
+ @Test
+ fun testDoneButtonSaysDone_noChanges() {
+ // GIVEN the editor dialog with no changes
+ `when`(dialogBuilder.build()).thenReturn(dialog)
+
+ group.channels = listOf(channel1, channel2)
+ controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
+ setOf(channel1, channel2), appIcon, null)
+
+ // WHEN the user proposes a change
+ controller.proposeEditForChannel(channel1, IMPORTANCE_NONE)
+
+ // THEN the "done" button has been updated to "apply"
+ verify(dialog).updateDoneButtonText(true /* hasChanges */)
+ }
+
+ @Test
+ fun testDoneButtonGoesBackToNormal_changeThenNoChange() {
+ val inOrderDialog = Mockito.inOrder(dialog)
+ // GIVEN the editor dialog with no changes
+ `when`(dialogBuilder.build()).thenReturn(dialog)
+
+ group.channels = listOf(channel1, channel2)
+ controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
+ setOf(channel1, channel2), appIcon, null)
+
+ // WHEN the user proposes a change
+ controller.proposeEditForChannel(channel1, IMPORTANCE_NONE)
+ // and WHEN the user sets the importance back to its original value
+ controller.proposeEditForChannel(channel1, channel1.importance)
+
+ // THEN the "done" button has been changed back to done
+ inOrderDialog.verify(dialog, times(1)).updateDoneButtonText(eq(true))
+ inOrderDialog.verify(dialog, times(1)).updateDoneButtonText(eq(false))
}
private val clickListener = object : NotificationInfo.OnSettingsClickListener {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 5813740..eeb912e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -123,6 +123,7 @@
@Mock private INotificationManager mINotificationManager;
@Mock private LauncherApps mLauncherApps;
@Mock private ShortcutManager mShortcutManager;
+ @Mock private ChannelEditorDialogController mChannelEditorDialogController;
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@Mock private CurrentUserContextTracker mContextTracker;
@Mock(answer = Answers.RETURNS_SELF)
@@ -144,7 +145,8 @@
mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager,
() -> mStatusBar, mHandler, mAccessibilityManager, mHighPriorityProvider,
- mINotificationManager, mLauncherApps, mShortcutManager, mContextTracker, mProvider);
+ mINotificationManager, mLauncherApps, mShortcutManager,
+ mChannelEditorDialogController, mContextTracker, mProvider);
mGutsManager.setUpWithPresenter(mPresenter, mStackScroller,
mCheckSaveListener, mOnSettingsClickListener);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -350,6 +352,7 @@
any(PackageManager.class),
any(INotificationManager.class),
eq(mVisualStabilityManager),
+ eq(mChannelEditorDialogController),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
@@ -381,6 +384,7 @@
any(PackageManager.class),
any(INotificationManager.class),
eq(mVisualStabilityManager),
+ eq(mChannelEditorDialogController),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
@@ -410,6 +414,7 @@
any(PackageManager.class),
any(INotificationManager.class),
eq(mVisualStabilityManager),
+ eq(mChannelEditorDialogController),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 98ef691..8ee86a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -30,17 +30,13 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
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 static org.mockito.Mockito.when;
@@ -53,13 +49,11 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.testing.PollingCheck;
import android.testing.TestableLooper;
import android.testing.UiThreadTest;
import android.view.LayoutInflater;
@@ -68,7 +62,6 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -120,6 +113,8 @@
private PackageManager mMockPackageManager;
@Mock
private VisualStabilityManager mVisualStabilityManager;
+ @Mock
+ private ChannelEditorDialogController mChannelEditorDialogController;
@Before
public void setUp() throws Exception {
@@ -185,6 +180,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -208,6 +204,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -227,6 +224,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -257,6 +255,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -277,6 +276,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -304,6 +304,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -326,6 +327,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -345,6 +347,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mDefaultNotificationChannel,
mDefaultNotificationChannelSet,
@@ -368,6 +371,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mDefaultNotificationChannel,
mDefaultNotificationChannelSet,
@@ -387,6 +391,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -407,6 +412,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -432,6 +438,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -452,6 +459,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -473,6 +481,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -486,6 +495,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -506,6 +516,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
mEntry,
@@ -531,6 +542,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
@@ -552,6 +564,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
@@ -573,6 +586,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -596,6 +610,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -614,6 +629,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -632,6 +648,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -653,6 +670,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -677,6 +695,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -701,6 +720,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -726,6 +746,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -751,6 +772,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -782,6 +804,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -814,6 +837,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -846,6 +870,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -881,6 +906,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -915,6 +941,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -940,6 +967,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -968,6 +996,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -999,6 +1028,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -1025,6 +1055,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -1056,6 +1087,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -1080,6 +1112,7 @@
mMockPackageManager,
mMockINotificationManager,
mVisualStabilityManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index c390e39..1bfebfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -98,6 +98,8 @@
private INotificationManager mMockINotificationManager;
@Mock
private PackageManager mMockPackageManager;
+ @Mock
+ private ChannelEditorDialogController mChannelEditorDialogController;
@Mock
private Icon mIcon;
@@ -160,6 +162,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -181,6 +184,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -207,6 +211,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -223,6 +228,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -250,6 +256,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -267,6 +274,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -291,6 +299,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -310,6 +319,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -327,6 +337,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -349,6 +360,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -365,6 +377,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
@@ -383,6 +396,7 @@
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mChannelEditorDialogController,
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 1cb4d89..c4bd1b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -37,6 +37,7 @@
import static org.mockito.Mockito.when;
import android.metrics.LogMaker;
+import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -152,7 +153,8 @@
NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
Settings.Secure.putInt(mContext.getContentResolver(),
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
- Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED, 1);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED,
+ 1, UserHandle.USER_CURRENT);
// Inject dependencies before initializing the layout
mDependency.injectMockDependency(VisualStabilityManager.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 67ad37b..1a6921a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -20,19 +20,24 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
+import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.SecureSetting;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -52,6 +57,13 @@
@SmallTest
public class AutoTileManagerTest extends SysuiTestCase {
+ private static final String TEST_SETTING = "setting";
+ private static final String TEST_SPEC = "spec";
+ private static final String TEST_SETTING_COMPONENT = "setting_component";
+ private static final String TEST_COMPONENT = "test_pkg/test_cls";
+ private static final String TEST_CUSTOM_SPEC = "custom(" + TEST_COMPONENT + ")";
+ private static final String SEPARATOR = AutoTileManager.SETTING_SEPARATOR;
+
@Mock private QSTileHost mQsTileHost;
@Mock private AutoAddTracker mAutoAddTracker;
@Mock private CastController mCastController;
@@ -61,7 +73,20 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
+
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_quickSettingsAutoAdd,
+ new String[] {
+ TEST_SETTING + SEPARATOR + TEST_SPEC,
+ TEST_SETTING_COMPONENT + SEPARATOR + TEST_CUSTOM_SPEC
+ }
+ );
+
+ mAutoTileManager = createAutoTileManager();
+ }
+
+ private AutoTileManager createAutoTileManager() {
+ return new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
Handler.createAsync(TestableLooper.get(this).getLooper()),
mock(HotspotController.class),
mock(DataSaverController.class),
@@ -137,4 +162,72 @@
mAutoTileManager.mCastCallback.onCastDevicesChanged();
verify(mQsTileHost, never()).addTile("cast");
}
+
+ @Test
+ public void testSettingTileAdded_onChanged() {
+ changeValue(TEST_SETTING, 1);
+ waitForIdleSync();
+ verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
+ verify(mQsTileHost).addTile(TEST_SPEC);
+ }
+
+ @Test
+ public void testSettingTileAddedComponent_onChanged() {
+ changeValue(TEST_SETTING_COMPONENT, 1);
+ waitForIdleSync();
+ verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
+ verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT));
+ }
+
+ @Test
+ public void testSettingTileAdded_onlyOnce() {
+ changeValue(TEST_SETTING, 1);
+ waitForIdleSync();
+ TestableLooper.get(this).processAllMessages();
+ changeValue(TEST_SETTING, 2);
+ waitForIdleSync();
+ verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
+ verify(mQsTileHost).addTile(TEST_SPEC);
+ }
+
+ @Test
+ public void testSettingTileNotAdded_onChangedTo0() {
+ changeValue(TEST_SETTING, 0);
+ waitForIdleSync();
+ verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
+ verify(mQsTileHost, never()).addTile(TEST_SPEC);
+ }
+
+ @Test
+ public void testSettingTileNotAdded_ifPreviouslyAdded() {
+ when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
+
+ changeValue(TEST_SETTING, 1);
+ waitForIdleSync();
+ verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
+ verify(mQsTileHost, never()).addTile(TEST_SPEC);
+ }
+
+ @Test
+ public void testEmptyArray_doesNotCrash() {
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_quickSettingsAutoAdd, new String[0]);
+ createAutoTileManager();
+ }
+
+ @Test
+ public void testMissingConfig_doesNotCrash() {
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_quickSettingsAutoAdd, null);
+ createAutoTileManager();
+ }
+
+ // Will only notify if it's listening
+ private void changeValue(String key, int value) {
+ SecureSetting s = mAutoTileManager.getSecureSettingForKey(key);
+ Settings.Secure.putInt(mContext.getContentResolver(), key, value);
+ if (s != null && s.isListening()) {
+ s.onChange(false);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 4b09aa6..57ef055 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -47,6 +47,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -207,7 +208,7 @@
NotificationWakeUpCoordinator coordinator =
new NotificationWakeUpCoordinator(
mock(HeadsUpManagerPhone.class),
- new StatusBarStateControllerImpl(),
+ new StatusBarStateControllerImpl(new UiEventLoggerFake()),
mKeyguardBypassController,
mDozeParameters);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index cc2d1c2..e04d25b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -83,6 +83,7 @@
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
+ @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Before
public void setUp() {
@@ -121,7 +122,7 @@
mNotificationPanelViewController,
mStatusBarViewFactory);
mController.setupExpandedStatusBar();
- mController.setService(mStatusBar);
+ mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index 05a4867..f83fbd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -55,6 +55,7 @@
MockitoAnnotations.initMocks(this);
mBatteryController = new BatteryControllerImpl(getContext(), mock(EnhancedEstimates.class),
mPowerManager, mBroadcastDispatcher, new Handler(), new Handler());
+ mBatteryController.init();
}
@Test
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index bfb6524..cbc5e14 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -27,7 +27,7 @@
"androidx.annotation_annotation",
"netd_aidl_interface-V3-java",
"netlink-client",
- "networkstack-aidl-interfaces-unstable-java",
+ "networkstack-aidl-interfaces-java",
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
@@ -109,6 +109,7 @@
manifest: "AndroidManifest_InProcess.xml",
// InProcessTethering is a replacement for Tethering
overrides: ["Tethering"],
+ apex_available: ["com.android.tethering"],
}
// Updatable tethering packaged as an application
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
index 24df5f6..20ccd2a 100644
--- a/packages/Tethering/apex/Android.bp
+++ b/packages/Tethering/apex/Android.bp
@@ -36,3 +36,12 @@
name: "com.android.tethering.certificate",
certificate: "com.android.tethering",
}
+
+override_apex {
+ name: "com.android.tethering.inprocess",
+ base: "com.android.tethering",
+ package_name: "com.android.tethering.inprocess",
+ apps: [
+ "InProcessTethering",
+ ],
+}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index ee6b9f1..d029d2b 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -67,6 +67,7 @@
stubs_defaults {
name: "framework-tethering-stubs-defaults",
srcs: [":framework-tethering-srcs"],
+ dist: { dest: "framework-tethering.txt" },
}
filegroup {
@@ -93,6 +94,15 @@
"framework-module-stubs-defaults-publicapi",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.public.latest",
+ removed_api_file: ":framework-tethering-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.public.latest",
+ },
+ },
}
droidstubs {
@@ -101,6 +111,15 @@
"framework-module-stubs-defaults-systemapi",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.system.latest",
+ removed_api_file: ":framework-tethering-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.system.latest",
+ },
+ },
}
droidstubs {
@@ -109,6 +128,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-tethering-stubs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-tethering.api.module-lib.latest",
+ removed_api_file: ":framework-tethering-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-tethering.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -123,16 +151,19 @@
name: "framework-tethering-stubs-publicapi",
srcs: [":framework-tethering-stubs-srcs-publicapi"],
defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+ dist: { dest: "framework-tethering.jar" },
}
java_library {
name: "framework-tethering-stubs-systemapi",
srcs: [":framework-tethering-stubs-srcs-systemapi"],
defaults: ["framework-module-stubs-lib-defaults-systemapi"],
+ dist: { dest: "framework-tethering.jar" },
}
java_library {
name: "framework-tethering-stubs-module_libs_api",
srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
- defaults: ["framework-module-stubs-lib-defaults-systemapi"],
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
+ dist: { dest: "framework-tethering.jar" },
}
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
index 12d6c2c..d074f15 100644
--- a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
+++ b/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="no_upstream_notification_title" msgid="5030042590486713460">"Tethering has no internet"</string>
+ <string name="no_upstream_notification_title" msgid="5030042590486713460">"टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन"</string>
<string name="no_upstream_notification_message" msgid="3843613362272973447">"यन्त्रहरू कनेक्ट गर्न सकिएन"</string>
<string name="no_upstream_notification_disable_button" msgid="6385491461813507624">"टेदरिङ निष्क्रिय पार्नुहोस्"</string>
<string name="upstream_roaming_notification_title" msgid="3015912166812283303">"हटस्पट वा टेदरिङ सक्रिय छ"</string>
diff --git a/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml
index 05b90692..528a1e5 100644
--- a/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml
+++ b/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml
@@ -16,9 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="no_upstream_notification_title" msgid="5030042590486713460">"無法透過數據連線連上網際網路"</string>
+ <string name="no_upstream_notification_title" msgid="5030042590486713460">"無法透過網路共用連上網際網路"</string>
<string name="no_upstream_notification_message" msgid="3843613362272973447">"裝置無法連線"</string>
- <string name="no_upstream_notification_disable_button" msgid="6385491461813507624">"關閉數據連線"</string>
- <string name="upstream_roaming_notification_title" msgid="3015912166812283303">"無線基地台或數據連線已開啟"</string>
+ <string name="no_upstream_notification_disable_button" msgid="6385491461813507624">"關閉網路共用"</string>
+ <string name="upstream_roaming_notification_title" msgid="3015912166812283303">"無線基地台或網路共用已開啟"</string>
<string name="upstream_roaming_notification_message" msgid="6724434706748439902">"使用漫遊服務可能須支付額外費用"</string>
</resources>
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
index 0a0aa21..1503244 100644
--- a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
+++ b/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="no_upstream_notification_title" msgid="611650570559011140">"Tethering has no internet"</string>
+ <string name="no_upstream_notification_title" msgid="611650570559011140">"टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन"</string>
<string name="no_upstream_notification_message" msgid="6508394877641864863">"यन्त्रहरू कनेक्ट गर्न सकिएन"</string>
<string name="no_upstream_notification_disable_button" msgid="7609346639290990508">"टेदरिङ निष्क्रिय पार्नुहोस्"</string>
<string name="upstream_roaming_notification_title" msgid="6032901176124830787">"हटस्पट वा टेदरिङ सक्रिय छ"</string>
diff --git a/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml
index ea01b94..cd653df 100644
--- a/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml
+++ b/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml
@@ -16,9 +16,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="no_upstream_notification_title" msgid="611650570559011140">"無法透過數據連線連上網際網路"</string>
+ <string name="no_upstream_notification_title" msgid="611650570559011140">"無法透過網路共用連上網際網路"</string>
<string name="no_upstream_notification_message" msgid="6508394877641864863">"裝置無法連線"</string>
- <string name="no_upstream_notification_disable_button" msgid="7609346639290990508">"關閉數據連線"</string>
- <string name="upstream_roaming_notification_title" msgid="6032901176124830787">"無線基地台或數據連線已開啟"</string>
+ <string name="no_upstream_notification_disable_button" msgid="7609346639290990508">"關閉網路共用"</string>
+ <string name="upstream_roaming_notification_title" msgid="6032901176124830787">"無線基地台或網路共用已開啟"</string>
<string name="upstream_roaming_notification_message" msgid="7599056263326217523">"使用漫遊服務可能須支付額外費用"</string>
</resources>
diff --git a/packages/Tethering/res/values-zh-rTW/strings.xml b/packages/Tethering/res/values-zh-rTW/strings.xml
index 9d738a7..50a50bf 100644
--- a/packages/Tethering/res/values-zh-rTW/strings.xml
+++ b/packages/Tethering/res/values-zh-rTW/strings.xml
@@ -16,11 +16,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="tethered_notification_title" msgid="6426563586025792944">"數據連線或無線基地台已啟用"</string>
+ <string name="tethered_notification_title" msgid="6426563586025792944">"網路共用或無線基地台已啟用"</string>
<string name="tethered_notification_message" msgid="64800879503420696">"輕觸即可進行設定。"</string>
- <string name="disable_tether_notification_title" msgid="3004509127903564191">"數據連線已停用"</string>
+ <string name="disable_tether_notification_title" msgid="3004509127903564191">"網路共用已停用"</string>
<string name="disable_tether_notification_message" msgid="6717523799293901476">"詳情請洽你的管理員"</string>
- <string name="notification_channel_tethering_status" msgid="2663463891530932727">"無線基地台與數據連線狀態"</string>
+ <string name="notification_channel_tethering_status" msgid="2663463891530932727">"無線基地台與網路共用狀態"</string>
<string name="no_upstream_notification_title" msgid="1204601824631788482"></string>
<string name="no_upstream_notification_message" msgid="8586582938243032621"></string>
<string name="no_upstream_notification_disable_button" msgid="8800919436924640822"></string>
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 83c99d2..9dda716 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -64,6 +64,13 @@
<string-array translatable="false" name="config_tether_dhcp_range">
</string-array>
+ <!-- Used to config periodic polls tether offload stats from tethering offload HAL to make the
+ data warnings work. 5000(ms) by default. If the device doesn't want to poll tether
+ offload stats, this should be -1. Note that this setting could be override by
+ runtime resource overlays.
+ -->
+ <integer translatable="false" name="config_tether_offload_poll_interval">5000</integer>
+
<!-- Array of ConnectivityManager.TYPE_{BLUETOOTH, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
WIFI} values allowable for tethering.
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 16ae8ad..4c78a74 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -24,6 +24,7 @@
<item type="array" name="config_tether_bluetooth_regexs"/>
<item type="array" name="config_tether_dhcp_range"/>
<item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+ <item type="integer" name="config_tether_offload_poll_interval"/>
<item type="array" name="config_tether_upstream_types"/>
<item type="bool" name="config_tether_upstream_automatic"/>
<!-- Configuration values for tethering entitlement check -->
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 049a9f6..23b8be1 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -37,6 +37,7 @@
import android.content.IntentFilter;
import android.net.util.SharedLog;
import android.os.Bundle;
+import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Parcel;
import android.os.PersistableBundle;
@@ -45,13 +46,12 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
-import android.util.ArraySet;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.StateMachine;
import java.io.PrintWriter;
+import java.util.BitSet;
/**
* Re-check tethering provisioning for enabled downstream tether types.
@@ -73,39 +73,37 @@
private final ComponentName mSilentProvisioningService;
private static final int MS_PER_HOUR = 60 * 60 * 1000;
+ private static final int DUMP_TIMEOUT = 10_000;
- // The ArraySet contains enabled downstream types, ex:
+ // The BitSet is the bit map of each enabled downstream types, ex:
// {@link TetheringManager.TETHERING_WIFI}
// {@link TetheringManager.TETHERING_USB}
// {@link TetheringManager.TETHERING_BLUETOOTH}
- private final ArraySet<Integer> mCurrentTethers;
+ private final BitSet mCurrentDownstreams;
private final Context mContext;
- private final int mPermissionChangeMessageCode;
private final SharedLog mLog;
private final SparseIntArray mEntitlementCacheValue;
private final Handler mHandler;
- private final StateMachine mTetherMasterSM;
// Key: TetheringManager.TETHERING_*(downstream).
// Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
- private final SparseIntArray mCellularPermitted;
+ private final SparseIntArray mCurrentEntitlementResults;
+ private final Runnable mPermissionChangeCallback;
private PendingIntent mProvisioningRecheckAlarm;
- private boolean mCellularUpstreamPermitted = true;
+ private boolean mLastCellularUpstreamPermitted = true;
private boolean mUsingCellularAsUpstream = false;
private boolean mNeedReRunProvisioningUi = false;
private OnUiEntitlementFailedListener mListener;
private TetheringConfigurationFetcher mFetcher;
- public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
- int permissionChangeMessageCode) {
-
+ public EntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
mContext = ctx;
mLog = log.forSubComponent(TAG);
- mCurrentTethers = new ArraySet<Integer>();
- mCellularPermitted = new SparseIntArray();
+ mCurrentDownstreams = new BitSet();
+ mCurrentEntitlementResults = new SparseIntArray();
mEntitlementCacheValue = new SparseIntArray();
- mTetherMasterSM = tetherMasterSM;
- mPermissionChangeMessageCode = permissionChangeMessageCode;
- mHandler = tetherMasterSM.getHandler();
+ mPermissionChangeCallback = callback;
+ mHandler = h;
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
null, mHandler);
mSilentProvisioningService = ComponentName.unflattenFromString(
@@ -144,13 +142,19 @@
* Check if cellular upstream is permitted.
*/
public boolean isCellularUpstreamPermitted() {
- // If provisioning is required and EntitlementManager don't know any downstream,
- // cellular upstream should not be allowed.
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) {
- return false;
- }
- return mCellularUpstreamPermitted;
+
+ return isCellularUpstreamPermitted(config);
+ }
+
+ private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) {
+ if (!isTetherProvisioningRequired(config)) return true;
+
+ // If provisioning is required and EntitlementManager doesn't know any downstreams,
+ // cellular upstream should not be allowed.
+ if (mCurrentDownstreams.isEmpty()) return false;
+
+ return mCurrentEntitlementResults.indexOfValue(TETHER_ERROR_NO_ERROR) > -1;
}
/**
@@ -164,29 +168,22 @@
public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
if (!isValidDownstreamType(downstreamType)) return;
- if (!mCurrentTethers.contains(downstreamType)) mCurrentTethers.add(downstreamType);
+ mCurrentDownstreams.set(downstreamType, true);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (isTetherProvisioningRequired(config)) {
- // If provisioning is required and the result is not available yet,
- // cellular upstream should not be allowed.
- if (mCellularPermitted.size() == 0) {
- mCellularUpstreamPermitted = false;
- }
- // If upstream is not cellular, provisioning app would not be launched
- // till upstream change to cellular.
- if (mUsingCellularAsUpstream) {
- if (showProvisioningUi) {
- runUiTetherProvisioning(downstreamType, config.activeDataSubId);
- } else {
- runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
- }
- mNeedReRunProvisioningUi = false;
+ if (!isTetherProvisioningRequired(config)) return;
+
+ // If upstream is not cellular, provisioning app would not be launched
+ // till upstream change to cellular.
+ if (mUsingCellularAsUpstream) {
+ if (showProvisioningUi) {
+ runUiTetherProvisioning(downstreamType, config.activeDataSubId);
} else {
- mNeedReRunProvisioningUi |= showProvisioningUi;
+ runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
}
+ mNeedReRunProvisioningUi = false;
} else {
- mCellularUpstreamPermitted = true;
+ mNeedReRunProvisioningUi |= showProvisioningUi;
}
}
@@ -195,14 +192,14 @@
*
* @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
- public void stopProvisioningIfNeeded(int type) {
- if (!isValidDownstreamType(type)) return;
+ public void stopProvisioningIfNeeded(int downstreamType) {
+ if (!isValidDownstreamType(downstreamType)) return;
- mCurrentTethers.remove(type);
+ mCurrentDownstreams.set(downstreamType, false);
// There are lurking bugs where the notion of "provisioning required" or
// "tethering supported" may change without without tethering being notified properly.
// Remove the mapping all the time no matter provisioning is required or not.
- removeDownstreamMapping(type);
+ removeDownstreamMapping(downstreamType);
}
/**
@@ -213,7 +210,7 @@
public void notifyUpstream(boolean isCellular) {
if (DBG) {
mLog.i("notifyUpstream: " + isCellular
- + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
+ + ", mLastCellularUpstreamPermitted: " + mLastCellularUpstreamPermitted
+ ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
}
mUsingCellularAsUpstream = isCellular;
@@ -231,7 +228,7 @@
}
private void maybeRunProvisioning(final TetheringConfiguration config) {
- if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) {
+ if (mCurrentDownstreams.isEmpty() || !isTetherProvisioningRequired(config)) {
return;
}
@@ -239,8 +236,9 @@
// are allowed. Therefore even if the silent check here ends in a failure and the UI later
// yields success, then the downstream that got a failure will re-evaluate as a result of
// the change and get the new correct value.
- for (Integer downstream : mCurrentTethers) {
- if (mCellularPermitted.indexOfKey(downstream) < 0) {
+ for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0;
+ downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) {
+ if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
if (mNeedReRunProvisioningUi) {
mNeedReRunProvisioningUi = false;
runUiTetherProvisioning(downstream, config.activeDataSubId);
@@ -286,7 +284,7 @@
mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
}
mEntitlementCacheValue.clear();
- mCellularPermitted.clear();
+ mCurrentEntitlementResults.clear();
// TODO: refine provisioning check to isTetherProvisioningRequired() ??
if (!config.hasMobileHotspotProvisionApp()
@@ -410,26 +408,25 @@
}
private void evaluateCellularPermission(final TetheringConfiguration config) {
- final boolean oldPermitted = mCellularUpstreamPermitted;
- mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config)
- || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
+ final boolean permitted = isCellularUpstreamPermitted(config);
if (DBG) {
- mLog.i("Cellular permission change from " + oldPermitted
- + " to " + mCellularUpstreamPermitted);
+ mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted
+ + " to " + permitted);
}
- if (mCellularUpstreamPermitted != oldPermitted) {
- mLog.log("Cellular permission change: " + mCellularUpstreamPermitted);
- mTetherMasterSM.sendMessage(mPermissionChangeMessageCode);
+ if (mLastCellularUpstreamPermitted != permitted) {
+ mLog.log("Cellular permission change: " + permitted);
+ mPermissionChangeCallback.run();
}
// Only schedule periodic re-check when tether is provisioned
// and the result is ok.
- if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
+ if (permitted && mCurrentEntitlementResults.size() > 0) {
scheduleProvisioningRechecks(config);
} else {
cancelTetherProvisioningRechecks();
}
+ mLastCellularUpstreamPermitted = permitted;
}
/**
@@ -441,10 +438,10 @@
*/
protected void addDownstreamMapping(int type, int resultCode) {
mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
- + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
- if (!mCurrentTethers.contains(type)) return;
+ + " ,TetherTypeRequested: " + mCurrentDownstreams.get(type));
+ if (!mCurrentDownstreams.get(type)) return;
- mCellularPermitted.put(type, resultCode);
+ mCurrentEntitlementResults.put(type, resultCode);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
evaluateCellularPermission(config);
}
@@ -455,7 +452,7 @@
*/
protected void removeDownstreamMapping(int type) {
mLog.i("removeDownstreamMapping: " + type);
- mCellularPermitted.delete(type);
+ mCurrentEntitlementResults.delete(type);
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
evaluateCellularPermission(config);
}
@@ -488,17 +485,25 @@
* @param pw {@link PrintWriter} is used to print formatted
*/
public void dump(PrintWriter pw) {
- pw.print("mCellularUpstreamPermitted: ");
- pw.println(mCellularUpstreamPermitted);
- for (Integer type : mCurrentTethers) {
- pw.print("Type: ");
- pw.print(typeString(type));
- if (mCellularPermitted.indexOfKey(type) > -1) {
- pw.print(", Value: ");
- pw.println(errorString(mCellularPermitted.get(type)));
- } else {
- pw.println(", Value: empty");
+ final ConditionVariable mWaiting = new ConditionVariable();
+ mHandler.post(() -> {
+ pw.print("isCellularUpstreamPermitted: ");
+ pw.println(isCellularUpstreamPermitted());
+ for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0;
+ type = mCurrentDownstreams.nextSetBit(type + 1)) {
+ pw.print("Type: ");
+ pw.print(typeString(type));
+ if (mCurrentEntitlementResults.indexOfKey(type) > -1) {
+ pw.print(", Value: ");
+ pw.println(errorString(mCurrentEntitlementResults.get(type)));
+ } else {
+ pw.println(", Value: empty");
+ }
}
+ mWaiting.open();
+ });
+ if (!mWaiting.block(DUMP_TIMEOUT)) {
+ pw.println("... dump timed out after " + DUMP_TIMEOUT + "ms");
}
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
index 1817f35..88c77b0 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
@@ -26,6 +26,8 @@
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.usage.NetworkStatsManager;
@@ -77,7 +79,6 @@
private static final boolean DBG = false;
private static final String ANYIP = "0.0.0.0";
private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
- private static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000;
@VisibleForTesting
enum StatsType {
@@ -134,11 +135,9 @@
private final Dependencies mDeps;
// TODO: Put more parameters in constructor into dependency object.
- static class Dependencies {
- int getPerformPollInterval() {
- // TODO: Consider make this configurable.
- return DEFAULT_PERFORM_POLL_INTERVAL_MS;
- }
+ interface Dependencies {
+ @NonNull
+ TetheringConfiguration getTetherConfig();
}
public OffloadController(Handler h, OffloadHardwareInterface hwi,
@@ -452,12 +451,16 @@
if (mHandler.hasCallbacks(mScheduledPollingTask)) {
mHandler.removeCallbacks(mScheduledPollingTask);
}
- mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval());
+ mHandler.postDelayed(mScheduledPollingTask,
+ mDeps.getTetherConfig().getOffloadPollInterval());
}
private boolean isPollingStatsNeeded() {
return started() && mRemainingAlertQuota > 0
- && !TextUtils.isEmpty(currentUpstreamInterface());
+ && !TextUtils.isEmpty(currentUpstreamInterface())
+ && mDeps.getTetherConfig() != null
+ && mDeps.getTetherConfig().getOffloadPollInterval()
+ >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
}
private boolean maybeUpdateDataLimit(String iface) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 0a95a5e..753abc9 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -62,7 +62,6 @@
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
-import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -268,12 +267,15 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
mTetherMasterSM.start();
- final NetworkStatsManager statsManager =
- (NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
mHandler = mTetherMasterSM.getHandler();
- mOffloadController = new OffloadController(mHandler,
- mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(),
- statsManager, mLog, new OffloadController.Dependencies());
+ mOffloadController = mDeps.getOffloadController(mHandler, mLog,
+ new OffloadController.Dependencies() {
+
+ @Override
+ public TetheringConfiguration getTetherConfig() {
+ return mConfig;
+ }
+ });
mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new LinkedHashSet<>();
@@ -282,8 +284,9 @@
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
- mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
- TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED);
+ mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
+ () -> mTetherMasterSM.sendMessage(
+ TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
stopTethering(downstream);
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index aeac437..9d4e747 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -78,6 +78,12 @@
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
"tether_enable_legacy_dhcp_server";
+ /**
+ * Default value that used to periodic polls tether offload stats from tethering offload HAL
+ * to make the data warnings work.
+ */
+ public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000;
+
public final String[] tetherableUsbRegexs;
public final String[] tetherableWifiRegexs;
public final String[] tetherableWifiP2pRegexs;
@@ -96,6 +102,8 @@
public final int activeDataSubId;
+ private final int mOffloadPollInterval;
+
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
@@ -129,6 +137,10 @@
R.integer.config_mobile_hotspot_provision_check_period,
0 /* No periodic re-check */);
+ mOffloadPollInterval = getResourceInteger(res,
+ R.integer.config_tether_offload_poll_interval,
+ DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+
configLog.log(toString());
}
@@ -189,6 +201,9 @@
dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges);
dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
+ pw.print("offloadPollInterval: ");
+ pw.println(mOffloadPollInterval);
+
dumpStringArray(pw, "provisioningApp", provisioningApp);
pw.print("provisioningAppNoUi: ");
pw.println(provisioningAppNoUi);
@@ -208,6 +223,7 @@
makeString(tetherableBluetoothRegexs)));
sj.add(String.format("isDunRequired:%s", isDunRequired));
sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
+ sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval));
sj.add(String.format("preferredUpstreamIfaceTypes:%s",
toIntArray(preferredUpstreamIfaceTypes)));
sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
@@ -246,6 +262,10 @@
return (tm != null) ? tm.isTetheringApnRequired() : false;
}
+ public int getOffloadPollInterval() {
+ return mOffloadPollInterval;
+ }
+
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types);
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index 9b54b5f..ce546c7 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -16,6 +16,7 @@
package com.android.networkstack.tethering;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.net.INetd;
@@ -47,6 +48,19 @@
}
/**
+ * Get a reference to the offload controller to be used by tethering.
+ */
+ @NonNull
+ public OffloadController getOffloadController(@NonNull Handler h,
+ @NonNull SharedLog log, @NonNull OffloadController.Dependencies deps) {
+ final NetworkStatsManager statsManager =
+ (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
+ return new OffloadController(h, getOffloadHardwareInterface(h, log),
+ getContext().getContentResolver(), statsManager, log, deps);
+ }
+
+
+ /**
* Get a reference to the UpstreamNetworkMonitor to be used by tethering.
*/
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
@@ -82,9 +96,9 @@
/**
* Get a reference to the EntitlementManager to be used by tethering.
*/
- public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what) {
- return new EntitlementManager(ctx, target, log, what);
+ public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ return new EntitlementManager(ctx, h, log, callback);
}
/**
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 8bd0edc..a692935 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -37,6 +37,8 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -45,7 +47,7 @@
import android.content.res.Resources;
import android.net.util.SharedLog;
import android.os.Bundle;
-import android.os.Message;
+import android.os.Handler;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.SystemProperties;
@@ -56,26 +58,22 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
-import java.util.ArrayList;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class EntitlementManagerTest {
- private static final int EVENT_EM_UPDATE = 1;
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
@@ -90,8 +88,8 @@
private final PersistableBundle mCarrierConfig = new PersistableBundle();
private final TestLooper mLooper = new TestLooper();
private Context mMockContext;
+ private Runnable mPermissionChangeCallback;
- private TestStateMachine mSM;
private WrappedEntitlementManager mEnMgr;
private TetheringConfiguration mConfig;
private MockitoSession mMockingSession;
@@ -112,9 +110,9 @@
public int uiProvisionCount = 0;
public int silentProvisionCount = 0;
- public WrappedEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what) {
- super(ctx, target, log, what);
+ public WrappedEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ super(ctx, h, log, callback);
}
public void reset() {
@@ -169,8 +167,9 @@
when(mLog.forSubComponent(anyString())).thenReturn(mLog);
mMockContext = new MockContext(mContext);
- mSM = new TestStateMachine();
- mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE);
+ mPermissionChangeCallback = spy(() -> { });
+ mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog,
+ mPermissionChangeCallback);
mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
mEnMgr.setTetheringConfigurationFetcher(() -> {
@@ -180,10 +179,6 @@
@After
public void tearDown() throws Exception {
- if (mSM != null) {
- mSM.quit();
- mSM = null;
- }
mMockingSession.finishMocking();
}
@@ -350,68 +345,105 @@
mEnMgr.reset();
}
+ private void assertPermissionChangeCallback(InOrder inOrder) {
+ inOrder.verify(mPermissionChangeCallback, times(1)).run();
+ }
+
+ private void assertNoPermissionChange(InOrder inOrder) {
+ inOrder.verifyNoMoreInteractions();
+ }
+
@Test
public void verifyPermissionResult() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: false -> true
+ assertPermissionChangeCallback(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
}
@Test
public void verifyPermissionIfAllNotApproved() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
mLooper.dispatchAll();
+ // Permitted: false -> false
+ assertNoPermissionChange(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
}
@Test
public void verifyPermissionIfAnyApproved() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
mEnMgr.notifyUpstream(true);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
- mLooper.dispatchAll();
+
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
+
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
-
}
@Test
public void verifyPermissionWhenProvisioningNotStarted() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ assertNoPermissionChange(inOrder);
setupForRequiredProvisioning();
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ assertNoPermissionChange(inOrder);
}
@Test
public void testRunTetherProvisioning() {
+ final InOrder inOrder = inOrder(mPermissionChangeCallback);
setupForRequiredProvisioning();
// 1. start ui provisioning, upstream is mobile
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
@@ -421,16 +453,22 @@
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 2. start no-ui provisioning
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(1, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 3. tear down mobile, then start ui provisioning
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
@@ -438,44 +476,58 @@
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
+
// 4. switch upstream back to mobile
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: true -> true
+ assertNoPermissionChange(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 5. tear down mobile, then switch SIM
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
mEnMgr.reevaluateSimCardProvisioning(mConfig);
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
+
// 6. switch upstream back to mobile again
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(3, mEnMgr.silentProvisionCount);
+ // Permitted: true -> false
+ assertPermissionChangeCallback(inOrder);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 7. start ui provisioning, upstream is mobile, downstream is ethernet
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ // Permitted: false -> true
+ assertPermissionChangeCallback(inOrder);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.reset();
+
// 8. downstream is invalid
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(0, mEnMgr.silentProvisionCount);
+ assertNoPermissionChange(inOrder);
mEnMgr.reset();
}
@@ -491,32 +543,4 @@
assertEquals(1, mEnMgr.uiProvisionCount);
verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
}
-
- public class TestStateMachine extends StateMachine {
- public final ArrayList<Message> messages = new ArrayList<>();
- private final State
- mLoggingState = new EntitlementManagerTest.TestStateMachine.LoggingState();
-
- class LoggingState extends State {
- @Override public void enter() {
- messages.clear();
- }
-
- @Override public void exit() {
- messages.clear();
- }
-
- @Override public boolean processMessage(Message msg) {
- messages.add(msg);
- return false;
- }
- }
-
- public TestStateMachine() {
- super("EntitlementManagerTest.TestStateMachine", mLooper.getLooper());
- addState(mLoggingState);
- setInitialState(mLoggingState);
- super.start();
- }
- }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
index 088a663..b291438 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -29,15 +29,15 @@
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE;
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID;
import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
+import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
import static com.android.testutils.MiscAssertsKt.assertContainsAll;
import static com.android.testutils.MiscAssertsKt.assertThrows;
-import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals;
+import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals;
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
@@ -63,10 +63,10 @@
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.RouteInfo;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
+import android.net.netstats.provider.NetworkStatsProvider;
import android.net.util.SharedLog;
import android.os.Handler;
-import android.os.Looper;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.test.mock.MockContentResolver;
@@ -75,7 +75,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.TestableNetworkStatsProviderCbBinder;
import org.junit.After;
import org.junit.Before;
@@ -109,17 +109,20 @@
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@Mock private NetworkStatsManager mStatsManager;
- @Mock private INetworkStatsProviderCallback mTetherStatsProviderCb;
+ @Mock private TetheringConfiguration mTetherConfig;
+ // Late init since methods must be called by the thread that created this object.
+ private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
private MockContentResolver mContentResolver;
+ private final TestLooper mTestLooper = new TestLooper();
private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() {
@Override
- int getPerformPollInterval() {
- return 0;
+ public TetheringConfiguration getTetherConfig() {
+ return mTetherConfig;
}
};
@@ -131,6 +134,7 @@
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
FakeSettingsProvider.clearSettingsProvider();
+ when(mTetherConfig.getOffloadPollInterval()).thenReturn(-1); // Disabled.
}
@After public void tearDown() throws Exception {
@@ -150,12 +154,16 @@
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
}
+ private void setOffloadPollInterval(int interval) {
+ when(mTetherConfig.getOffloadPollInterval()).thenReturn(interval);
+ }
+
private void waitForIdle() {
- HandlerUtilsKt.waitForIdle(new Handler(Looper.getMainLooper()), WAIT_FOR_IDLE_TIMEOUT);
+ mTestLooper.dispatchAll();
}
private OffloadController makeOffloadController() throws Exception {
- OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
+ OffloadController offload = new OffloadController(new Handler(mTestLooper.getLooper()),
mHardware, mContentResolver, mStatsManager, new SharedLog("test"), mDeps);
final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider>
tetherStatsProviderCaptor =
@@ -164,6 +172,7 @@
tetherStatsProviderCaptor.capture());
mTetherStatsProvider = tetherStatsProviderCaptor.getValue();
assertNotNull(mTetherStatsProvider);
+ mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder();
mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb);
return offload;
}
@@ -352,9 +361,9 @@
stacked.setInterfaceName("stacked");
stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null,
- RTN_UNICAST));
+ RTN_UNICAST));
stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null,
- RTN_UNICAST));
+ RTN_UNICAST));
assertTrue(lp.addStackedLink(stacked));
offload.setUpstreamLinkProperties(lp);
// No change in local addresses means no call to setLocalPrefixes().
@@ -459,20 +468,12 @@
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321));
- assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats));
- assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats));
-
- final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass(
- NetworkStats.class);
- final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass(
- NetworkStats.class);
+ assertNetworkStatsEquals(expectedIfaceStats, ifaceStats);
+ assertNetworkStatsEquals(expectedUidStats, uidStats);
// Force pushing stats update to verify the stats reported.
mTetherStatsProvider.pushTetherStats();
- verify(mTetherStatsProviderCb, times(1))
- .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
- assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue()));
- assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue()));
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats);
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
new ForwardedStats(100000, 100000));
@@ -498,11 +499,10 @@
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321));
- assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu));
- assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu));
+ assertNetworkStatsEquals(expectedIfaceStatsAccu, ifaceStatsAccu);
+ assertNetworkStatsEquals(expectedUidStatsAccu, uidStatsAccu);
// Verify that only diff of stats is reported.
- reset(mTetherStatsProviderCb);
mTetherStatsProvider.pushTetherStats();
final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2)
.addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0))
@@ -511,10 +511,8 @@
final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2)
.addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0))
.addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000));
- verify(mTetherStatsProviderCb, times(1))
- .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
- assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue()));
- assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue()));
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff,
+ expectedUidStatsDiff);
}
@Test
@@ -591,7 +589,7 @@
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
callback.onStoppedLimitReached();
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
}
@Test
@@ -695,8 +693,8 @@
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
// TODO: verify the exact stats reported.
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
- verifyNoMoreInteractions(mTetherStatsProviderCb);
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
+ mTetherStatsProviderCb.assertNoCallback();
verifyNoMoreInteractions(mHardware);
}
@@ -760,8 +758,8 @@
// Verify forwarded stats behaviour.
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
- verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any());
- verifyNoMoreInteractions(mTetherStatsProviderCb);
+ mTetherStatsProviderCb.expectNotifyStatsUpdated();
+ mTetherStatsProviderCb.assertNoCallback();
// TODO: verify local prefixes and downstreams are also pushed to the HAL.
verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
@@ -780,4 +778,50 @@
verifyNoMoreInteractions(mHardware);
}
+ @Test
+ public void testOnSetAlert() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+ setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ // Initialize with fake eth upstream.
+ final String ethernetIface = "eth1";
+ InOrder inOrder = inOrder(mHardware);
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+ // Previous upstream was null, so no stats are fetched.
+ inOrder.verify(mHardware, never()).getForwardedStats(any());
+
+ // Verify that set quota to 0 will immediately triggers an callback.
+ mTetherStatsProvider.onSetAlert(0);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that notifyAlertReached never fired if quota is not yet reached.
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
+ new ForwardedStats(0, 0));
+ mTetherStatsProvider.onSetAlert(100);
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+
+ // Verify that notifyAlertReached fired when quota is reached.
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
+ new ForwardedStats(50, 50));
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that set quota with UNLIMITED won't trigger any callback, and won't fetch
+ // any stats since the polling is stopped.
+ reset(mHardware);
+ mTetherStatsProvider.onSetAlert(NetworkStatsProvider.QUOTA_UNLIMITED);
+ mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+ verify(mHardware, never()).getForwardedStats(any());
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index 07ddea4..e8ba5b8 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -115,6 +115,8 @@
when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn(
new String[0]);
+ when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn(
+ TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
.thenReturn(new String[]{ "test_wlan\\d" });
@@ -314,6 +316,23 @@
}
@Test
+ public void testOffloadIntervalByResource() {
+ final TetheringConfiguration intervalByDefault =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertEquals(TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS,
+ intervalByDefault.getOffloadPollInterval());
+
+ final int[] testOverrides = {0, 3000, -1};
+ for (final int override : testOverrides) {
+ when(mResources.getInteger(R.integer.config_tether_offload_poll_interval)).thenReturn(
+ override);
+ final TetheringConfiguration overrideByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertEquals(override, overrideByRes.getOffloadPollInterval());
+ }
+ }
+
+ @Test
public void testGetResourcesBySubId() {
setUpResourceForSubId();
final TetheringConfiguration cfg = new TetheringConfiguration(
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 0363f5f..fa260a4 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -150,6 +150,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.ArrayList;
@@ -212,6 +214,9 @@
private Tethering mTethering;
private PhoneStateListener mPhoneStateListener;
private InterfaceConfigurationParcel mInterfaceConfiguration;
+ private TetheringConfiguration mConfig;
+ private EntitlementManager mEntitleMgr;
+ private OffloadController mOffloadCtrl;
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
@@ -297,8 +302,9 @@
}
}
- private class MockTetheringConfiguration extends TetheringConfiguration {
- MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ // MyTetheringConfiguration is used to override static method for testing.
+ private class MyTetheringConfiguration extends TetheringConfiguration {
+ MyTetheringConfiguration(Context ctx, SharedLog log, int id) {
super(ctx, log, id);
}
@@ -328,6 +334,15 @@
}
@Override
+ public OffloadController getOffloadController(Handler h, SharedLog log,
+ OffloadController.Dependencies deps) {
+ mOffloadCtrl = spy(super.getOffloadController(h, log, deps));
+ // Return real object here instead of mock because
+ // testReportFailCallbackIfOffloadNotSupported depend on real OffloadController object.
+ return mOffloadCtrl;
+ }
+
+ @Override
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
StateMachine target, SharedLog log, int what) {
mUpstreamNetworkMonitorMasterSM = target;
@@ -352,6 +367,13 @@
}
@Override
+ public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ Runnable callback) {
+ mEntitleMgr = spy(super.getEntitlementManager(ctx, h, log, callback));
+ return mEntitleMgr;
+ }
+
+ @Override
public boolean isTetheringSupported() {
return true;
}
@@ -359,7 +381,8 @@
@Override
public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
int subId) {
- return new MockTetheringConfiguration(ctx, log, subId);
+ mConfig = spy(new MyTetheringConfiguration(ctx, log, subId));
+ return mConfig;
}
@Override
@@ -1726,6 +1749,19 @@
verify(mNotificationUpdater, never()).onUpstreamCapabilitiesChanged(any());
}
+ @Test
+ public void testDumpTetheringLog() throws Exception {
+ final FileDescriptor mockFd = mock(FileDescriptor.class);
+ final PrintWriter mockPw = mock(PrintWriter.class);
+ runUsbTethering(null);
+ mLooper.startAutoDispatch();
+ mTethering.dump(mockFd, mockPw, new String[0]);
+ verify(mConfig).dump(any());
+ verify(mEntitleMgr).dump(any());
+ verify(mOffloadCtrl).dump(any());
+ mLooper.stopAutoDispatch();
+ }
+
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}
diff --git a/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml b/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
index 8e80c9d..63ba20e 100644
--- a/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeTaperedRectOverlay/res/values/config.xml
@@ -24,6 +24,5 @@
<!-- Corner radius for bottom sheet system dialogs -->
<dimen name="config_bottomDialogCornerRadius">0dp</dimen>
<!-- Tile stroke width -->
- <dimen name="config_qsTileStrokeWidthInactive">10dp</dimen>
-
+ <dimen name="config_qsTileStrokeWidthInactive">1dp</dimen>
</resources>
diff --git a/services/Android.bp b/services/Android.bp
index 6d637be..882085a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -1,3 +1,10 @@
+java_defaults {
+ name: "services_defaults",
+ plugins: [
+ "error_prone_android_framework",
+ ],
+}
+
filegroup {
name: "services-main-sources",
srcs: ["java/**/*.java"],
@@ -73,6 +80,8 @@
"services.usb",
"services.voiceinteraction",
"services.wifi",
+ "service-blobstore",
+ "service-jobscheduler",
"android.hidl.base-V1.0-java",
],
@@ -83,7 +92,6 @@
// Uncomment to enable output of certain warnings (deprecated, unchecked)
//javacflags: ["-Xlint"],
-
}
// native library
@@ -128,13 +136,13 @@
removed_api_file: "api/removed.txt",
},
last_released: {
- api_file: ":last-released-system-server-api",
- removed_api_file: "api/removed.txt",
+ api_file: ":android.api.system-server.latest",
+ removed_api_file: ":removed.api.system-server.latest",
baseline_file: ":system-server-api-incompatibilities-with-last-released"
},
api_lint: {
enabled: true,
- new_since: ":last-released-system-server-api",
+ new_since: ":android.api.system-server.latest",
baseline_file: "api/lint-baseline.txt",
},
},
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index 284a2f2..21a0c748 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.accessibility",
+ defaults: ["services_defaults"],
srcs: [":services.accessibility-sources"],
libs: ["services.core"],
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index edb4445..0f98992d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -94,8 +94,10 @@
if (userState == null) return;
final long identity = Binder.clearCallingIdentity();
try {
- int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+ int flags = Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_INCLUDE_CAPABILITIES;
if (userState.getBindInstantServiceAllowedLocked()) {
flags |= Context.BIND_ALLOW_INSTANT;
}
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
index e14e1df..c12f62f 100644
--- a/services/appprediction/Android.bp
+++ b/services/appprediction/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.appprediction",
+ defaults: ["services_defaults"],
srcs: [":services.appprediction-sources"],
libs: ["services.core"],
}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 0b3899d..fdc5f81 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -120,7 +120,7 @@
this::removeAppPredictionSessionInfo));
}
final boolean serviceExists = resolveService(sessionId, s ->
- s.onCreatePredictionSession(context, sessionId));
+ s.onCreatePredictionSession(context, sessionId), true);
if (!serviceExists) {
mSessionInfos.remove(sessionId);
}
@@ -132,7 +132,7 @@
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event));
+ resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
}
/**
@@ -142,7 +142,7 @@
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
resolveService(sessionId, s ->
- s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
+ s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
}
/**
@@ -151,7 +151,7 @@
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback));
+ resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
}
/**
@@ -161,7 +161,7 @@
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.registerPredictionUpdates(sessionId, callback));
+ s.registerPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.addCallbackLocked(callback);
@@ -175,7 +175,7 @@
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.unregisterPredictionUpdates(sessionId, callback));
+ s.unregisterPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.removeCallbackLocked(callback);
@@ -187,7 +187,7 @@
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId));
+ resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
}
/**
@@ -196,7 +196,7 @@
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
final boolean serviceExists = resolveService(sessionId, s ->
- s.onDestroyPredictionSession(sessionId));
+ s.onDestroyPredictionSession(sessionId), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (serviceExists && sessionInfo != null) {
sessionInfo.destroy();
@@ -304,7 +304,8 @@
@GuardedBy("mLock")
@Nullable
protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
- @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+ @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
+ boolean sendImmediately) {
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (sessionInfo == null) return false;
if (sessionInfo.mUsesPeopleService) {
@@ -322,7 +323,13 @@
} else {
final RemoteAppPredictionService service = getRemoteServiceLocked();
if (service != null) {
- service.scheduleOnResolvedService(cb);
+ // TODO(b/155887722): implement a priority system so that latency-sensitive
+ // requests gets executed first.
+ if (sendImmediately) {
+ service.executeOnResolvedService(cb);
+ } else {
+ service.scheduleOnResolvedService(cb);
+ }
}
return service != null;
}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index ceb1caf..a57ff11 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -80,6 +80,13 @@
}
/**
+ * Execute async request on remote service immediately instead of sending it to Handler queue.
+ */
+ public void executeOnResolvedService(@NonNull AsyncRequest<IPredictionService> request) {
+ executeAsyncRequest(request);
+ }
+
+ /**
* Failure callback
*/
public interface RemoteAppPredictionServiceCallbacks
diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp
index 54cf6ce..83a9aa4 100644
--- a/services/appwidget/Android.bp
+++ b/services/appwidget/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.appwidget",
+ defaults: ["services_defaults"],
srcs: [":services.appwidget-sources"],
libs: ["services.core"],
}
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index 539eb1a..1e65e84 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.autofill",
+ defaults: ["services_defaults"],
srcs: [":services.autofill-sources"],
libs: ["services.core"],
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 3612e09..3282870 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -17,17 +17,17 @@
package com.android.server.autofill;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.Handler;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
-import java.util.Collections;
import java.util.Optional;
import java.util.function.Consumer;
@@ -46,8 +46,12 @@
@NonNull
private final Handler mHandler;
+ @Nullable
@GuardedBy("mLock")
private AutofillInlineSuggestionsRequestSession mSession;
+ @Nullable
+ @GuardedBy("mLock")
+ private InlineFillUi mInlineFillUi;
AutofillInlineSessionController(InputMethodManagerInternal inputMethodManagerInternal,
int userId, ComponentName componentName, Handler handler, Object lock) {
@@ -72,16 +76,16 @@
// TODO(b/151123764): rename the method to better reflect what it does.
if (mSession != null) {
// Send an empty response to IME and destroy the existing session.
- mSession.onInlineSuggestionsResponseLocked(mSession.getAutofillIdLocked(),
- new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+ mSession.onInlineSuggestionsResponseLocked(
+ InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
mSession.destroySessionLocked();
+ mInlineFillUi = null;
}
// TODO(b/151123764): consider reusing the same AutofillInlineSession object for the
// same field.
mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId,
mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras);
mSession.onCreateInlineSuggestionsRequestLocked();
-
}
/**
@@ -101,30 +105,63 @@
/**
* Requests the IME to hide the current suggestions, if any. Returns true if the message is sent
- * to the IME.
+ * to the IME. This only hides the UI temporarily. For example if user starts typing/deleting
+ * characters, new filterText will kick in and may revive the suggestion UI.
*/
@GuardedBy("mLock")
boolean hideInlineSuggestionsUiLocked(@NonNull AutofillId autofillId) {
if (mSession != null) {
- return mSession.onInlineSuggestionsResponseLocked(autofillId,
- new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+ return mSession.onInlineSuggestionsResponseLocked(InlineFillUi.emptyUi(autofillId));
}
return false;
}
/**
- * Requests showing the inline suggestion in the IME when the IME becomes visible and is focused
- * on the {@code autofillId}.
- *
- * @return false if there is no session, or if the IME callback is not available in the session.
+ * Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
+ * well.
*/
@GuardedBy("mLock")
- boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
- // TODO(b/151123764): rename the method to better reflect what it does.
- if (mSession != null) {
- return mSession.onInlineSuggestionsResponseLocked(autofillId,
- inlineSuggestionsResponse);
+ boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
+ mInlineFillUi = null;
+ return hideInlineSuggestionsUiLocked(autofillId);
+ }
+
+ /**
+ * Updates the inline fill UI with the filter text. It'll send updated inline suggestions to
+ * the IME.
+ */
+ @GuardedBy("mLock")
+ boolean filterInlineFillUiLocked(@NonNull AutofillId autofillId, @Nullable String filterText) {
+ if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
+ mInlineFillUi.setFilterText(filterText);
+ return requestImeToShowInlineSuggestionsLocked();
+ }
+ return false;
+ }
+
+ /**
+ * Set the current inline fill UI. It'll request the IME to show the inline suggestions when
+ * the IME becomes visible and is focused on the {@code autofillId}.
+ *
+ * @return false if the suggestions are not sent to IME because there is no session, or if the
+ * IME callback is not available in the session.
+ */
+ @GuardedBy("mLock")
+ boolean setInlineFillUiLocked(@NonNull InlineFillUi inlineFillUi) {
+ mInlineFillUi = inlineFillUi;
+ return requestImeToShowInlineSuggestionsLocked();
+ }
+
+ /**
+ * Sends the suggestions from the current inline fill UI to the IME.
+ *
+ * @return false if the suggestions are not sent to IME because there is no session, or if the
+ * IME callback is not available in the session.
+ */
+ @GuardedBy("mLock")
+ private boolean requestImeToShowInlineSuggestionsLocked() {
+ if (mSession != null && mInlineFillUi != null) {
+ return mSession.onInlineSuggestionsResponseLocked(mInlineFillUi);
}
return false;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index ce11c76..0bf8993 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -27,7 +27,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
@@ -37,6 +36,7 @@
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.lang.ref.WeakReference;
@@ -105,7 +105,7 @@
private boolean mImeInputViewStarted;
@GuardedBy("mLock")
@Nullable
- private InlineSuggestionsResponse mInlineSuggestionsResponse;
+ private InlineFillUi mInlineFillUi;
@GuardedBy("mLock")
private boolean mPreviousResponseIsNotEmpty;
@@ -155,18 +155,20 @@
* @return false if the IME callback is not available.
*/
@GuardedBy("mLock")
- boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
+ boolean onInlineSuggestionsResponseLocked(@NonNull InlineFillUi inlineFillUi) {
if (mDestroyed) {
return false;
}
- if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked called for:" + autofillId);
+ if (sDebug) {
+ Slog.d(TAG,
+ "onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
+ }
if (mImeRequest == null || mResponseCallback == null) {
return false;
}
// TODO(b/151123764): each session should only correspond to one field.
- mAutofillId = autofillId;
- mInlineSuggestionsResponse = inlineSuggestionsResponse;
+ mAutofillId = inlineFillUi.getAutofillId();
+ mInlineFillUi = inlineFillUi;
maybeUpdateResponseToImeLocked();
return true;
}
@@ -190,12 +192,12 @@
if (mDestroyed) {
return;
}
- if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
+ if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
new InlineSuggestionsRequestCallbackImpl(this));
mTimeoutCallback = () -> {
- Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
+ Slog.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
handleOnReceiveImeRequest(null, null);
};
mHandler.postDelayed(mTimeoutCallback, CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS);
@@ -206,7 +208,7 @@
*/
@GuardedBy("mLock")
private void maybeUpdateResponseToImeLocked() {
- if (sVerbose) Log.v(TAG, "maybeUpdateResponseToImeLocked called");
+ if (sVerbose) Slog.v(TAG, "maybeUpdateResponseToImeLocked called");
if (mDestroyed || mResponseCallback == null) {
return;
}
@@ -216,18 +218,19 @@
// Although the inline suggestions should disappear when IME hides which removes them
// from the view hierarchy, but we still send an empty response to be extra safe.
- if (sVerbose) Log.v(TAG, "Send empty inline response");
+ if (sVerbose) Slog.v(TAG, "Send empty inline response");
updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
mPreviousResponseIsNotEmpty = false;
- } else if (mImeInputViewStarted && mInlineSuggestionsResponse != null && match(mAutofillId,
+ } else if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
mImeCurrentFieldId)) {
// 2. if IME is visible, and response is not null, send the response
- boolean isEmptyResponse = mInlineSuggestionsResponse.getInlineSuggestions().isEmpty();
+ InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
+ boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
// No-op if both the previous response and current response are empty.
return;
}
- updateResponseToImeUncheckLocked(mInlineSuggestionsResponse);
+ updateResponseToImeUncheckLocked(response);
mPreviousResponseIsNotEmpty = !isEmptyResponse;
}
}
@@ -240,7 +243,7 @@
if (mDestroyed) {
return;
}
- if (sDebug) Log.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
+ if (sDebug) Slog.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
try {
mResponseCallback.onInlineSuggestionsResponse(mAutofillId, response);
} catch (RemoteException e) {
@@ -262,7 +265,7 @@
mImeRequestReceived = true;
if (mTimeoutCallback != null) {
- if (sVerbose) Log.v(TAG, "removing timeout callback");
+ if (sVerbose) Slog.v(TAG, "removing timeout callback");
mHandler.removeCallbacks(mTimeoutCallback);
mTimeoutCallback = null;
}
@@ -333,7 +336,7 @@
@BinderThread
@Override
public void onInlineSuggestionsUnsupported() throws RemoteException {
- if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsUnsupported() called.");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -346,7 +349,7 @@
@Override
public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
IInlineSuggestionsResponseCallback callback) {
- if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsRequest() received: " + request);
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -357,7 +360,7 @@
@Override
public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
- if (sVerbose) Log.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
+ if (sVerbose) Slog.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -369,14 +372,14 @@
@Override
public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
if (sVerbose) {
- Log.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
+ Slog.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
}
}
@BinderThread
@Override
public void onInputMethodStartInputView() {
- if (sVerbose) Log.v(TAG, "onInputMethodStartInputView() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodStartInputView() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -388,7 +391,7 @@
@BinderThread
@Override
public void onInputMethodFinishInputView() {
- if (sVerbose) Log.v(TAG, "onInputMethodFinishInputView() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodFinishInputView() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
@@ -399,7 +402,7 @@
@Override
public void onInputMethodFinishInput() throws RemoteException {
- if (sVerbose) Log.v(TAG, "onInputMethodFinishInput() received");
+ if (sVerbose) Slog.v(TAG, "onInputMethodFinishInput() received");
final AutofillInlineSuggestionsRequestSession session = mSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1bc026c..1aeb19b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -260,7 +260,7 @@
if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
// Check if it's enabled for augmented autofill
- if (isAugmentedAutofillServiceAvailableLocked()
+ if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
&& isWhitelistedForAugmentedAutofillLocked(componentName)) {
return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 6cec8d8..851e4cc 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -48,17 +48,15 @@
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
-import com.android.server.autofill.ui.InlineSuggestionFactory;
+import com.android.server.autofill.ui.InlineFillUi;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -149,7 +147,7 @@
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
- @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
+ @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
long requestTime = SystemClock.elapsedRealtime();
@@ -173,7 +171,8 @@
mCallbacks.resetLastResponse();
maybeRequestShowInlineSuggestions(sessionId,
inlineSuggestionsRequest, inlineSuggestionsData,
- clientState, focusedId, inlineSuggestionsCallback,
+ clientState, focusedId, focusedValue,
+ inlineSuggestionsCallback,
client, onErrorCallback, remoteRenderService);
requestAutofill.complete(null);
}
@@ -239,8 +238,8 @@
private void maybeRequestShowInlineSuggestions(int sessionId,
@Nullable InlineSuggestionsRequest request,
@Nullable List<Dataset> inlineSuggestionsData, @Nullable Bundle clientState,
- @NonNull AutofillId focusedId,
- @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
+ @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue,
+ @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
@NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
@@ -250,10 +249,14 @@
}
mCallbacks.setLastResponse(sessionId);
- final InlineSuggestionsResponse inlineSuggestionsResponse =
- InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
- request, inlineSuggestionsData, focusedId,
- new InlineSuggestionFactory.InlineSuggestionUiCallback() {
+ final String filterText =
+ focusedValue != null && focusedValue.isText()
+ ? focusedValue.getTextValue().toString() : null;
+
+ final InlineFillUi inlineFillUi =
+ InlineFillUi.forAugmentedAutofill(
+ request, inlineSuggestionsData, focusedId, filterText,
+ new InlineFillUi.InlineSuggestionUiCallback() {
@Override
public void autofill(Dataset dataset) {
mCallbacks.logAugmentedAutofillSelected(sessionId,
@@ -265,8 +268,8 @@
&& fieldIds.get(0).equals(focusedId);
client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
hideHighlight);
- inlineSuggestionsCallback.apply(new InlineSuggestionsResponse(
- Collections.EMPTY_LIST));
+ inlineSuggestionsCallback.apply(
+ InlineFillUi.emptyUi(focusedId));
} catch (RemoteException e) {
Slog.w(TAG, "Encounter exception autofilling the values");
}
@@ -283,11 +286,7 @@
}
}, onErrorCallback, remoteRenderService);
- if (inlineSuggestionsResponse == null) {
- Slog.w(TAG, "InlineSuggestionFactory created null response");
- return;
- }
- if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) {
+ if (inlineSuggestionsCallback.apply(inlineFillUi)) {
mCallbacks.logAugmentedAutofillShown(sessionId, clientState);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
index 255adcd..617c111 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java
@@ -47,7 +47,7 @@
private static final String TAG = "RemoteInlineSuggestionRenderService";
- private final int mIdleUnbindTimeoutMs = 5000;
+ private final long mIdleUnbindTimeoutMs = PERMANENT_BOUND_TIMEOUT_MS;
RemoteInlineSuggestionRenderService(Context context, ComponentName componentName,
String serviceInterface, int userId, InlineSuggestionRenderCallbacks callback,
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 35089d6..ff4e7ba 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -94,7 +94,6 @@
import android.view.autofill.IAutoFillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
import android.view.inputmethod.InlineSuggestionsRequest;
-import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -102,7 +101,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.server.autofill.ui.AutoFillUI;
-import com.android.server.autofill.ui.InlineSuggestionFactory;
+import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.autofill.ui.PendingUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -325,7 +324,7 @@
@GuardedBy("mLock")
private CountDownLatch mCountDownLatch = new CountDownLatch(0);
- @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(
+ @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(ViewState viewState,
boolean isInlineRequest) {
mCountDownLatch = new CountDownLatch(isInlineRequest ? 2 : 1);
mPendingFillRequest = null;
@@ -338,6 +337,7 @@
mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
mCountDownLatch.countDown();
maybeRequestFillLocked();
+ viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} : null;
}
@@ -716,18 +716,23 @@
mService.getRemoteInlineSuggestionRenderServiceLocked();
if (isInlineSuggestionsEnabledByAutofillProviderLocked() && remoteRenderService != null) {
Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
- mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ true);
+ mAssistReceiver.newAutofillRequestLocked(viewState,
+ /*isInlineRequest=*/ true);
if (inlineSuggestionsRequestConsumer != null) {
final AutofillId focusedId = mCurrentViewId;
remoteRenderService.getInlineSuggestionsRendererInfo(
new RemoteCallback((extras) -> {
- mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
- focusedId, inlineSuggestionsRequestConsumer, extras);
- }
- ));
+ synchronized (mLock) {
+ mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
+ focusedId, inlineSuggestionsRequestConsumer, extras);
+ }
+ }, mHandler)
+ );
+ viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
}
} else {
- mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ false);
+ mAssistReceiver.newAutofillRequestLocked(viewState,
+ /*isInlineRequest=*/ false);
}
// Now request the assist structure data.
@@ -2368,7 +2373,9 @@
*/
@GuardedBy("mLock")
private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id) {
- if (mResponses == null) {
+ final ViewState currentView = mViewStates.get(id);
+ if (mResponses == null && currentView != null
+ && (currentView.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0) {
return true;
}
@@ -2654,10 +2661,20 @@
}
} else if (viewState.id.equals(this.mCurrentViewId)
&& (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
- requestShowInlineSuggestionsLocked(viewState.getResponse(), filterText);
+ if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
+ final FillResponse response = viewState.getResponse();
+ if (response != null) {
+ response.getDatasets().clear();
+ }
+ mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
+ } else {
+ mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
+ }
} else if (viewState.id.equals(this.mCurrentViewId)
&& (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
if (!TextUtils.isEmpty(filterText)) {
+ // TODO: we should be able to replace this with controller#filterInlineFillUiLocked
+ // to accomplish filtering for augmented autofill.
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
}
}
@@ -2808,26 +2825,15 @@
return false;
}
- final ViewState currentView = mViewStates.get(focusedId);
- if ((currentView.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
- response.getDatasets().clear();
- }
- InlineSuggestionsResponse inlineSuggestionsResponse =
- InlineSuggestionFactory.createInlineSuggestionsResponse(
- inlineSuggestionsRequest.get(), response, filterText, focusedId,
- this, () -> {
- synchronized (mLock) {
- mInlineSessionController.hideInlineSuggestionsUiLocked(
- focusedId);
- }
- }, remoteRenderService);
- if (inlineSuggestionsResponse == null) {
- Slog.w(TAG, "InlineSuggestionFactory created null response");
- return false;
- }
-
- return mInlineSessionController.onInlineSuggestionsResponseLocked(focusedId,
- inlineSuggestionsResponse);
+ InlineFillUi inlineFillUi = InlineFillUi.forAutofill(
+ inlineSuggestionsRequest.get(), response, focusedId, filterText,
+ /*uiCallback*/this, /*onErrorCallback*/ () -> {
+ synchronized (mLock) {
+ mInlineSessionController.hideInlineSuggestionsUiLocked(
+ focusedId);
+ }
+ }, remoteRenderService);
+ return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
}
boolean isDestroyed() {
@@ -3111,11 +3117,10 @@
final AutofillId focusedId = mCurrentViewId;
- final Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsResponseCallback =
+ final Function<InlineFillUi, Boolean> inlineSuggestionsResponseCallback =
response -> {
synchronized (mLock) {
- return mInlineSessionController.onInlineSuggestionsResponseLocked(
- focusedId, response);
+ return mInlineSessionController.setInlineFillUiLocked(response);
}
};
final Consumer<InlineSuggestionsRequest> requestAugmentedAutofill =
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 9114576..adb1e3e 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -80,6 +80,8 @@
public static final int STATE_CHAR_REMOVED = 0x4000;
/** Showing inline suggestions is not allowed for this View. */
public static final int STATE_INLINE_DISABLED = 0x8000;
+ /** The View is waiting for an inline suggestions request from IME.*/
+ public static final int STATE_PENDING_CREATE_INLINE_REQUEST = 0x10000;
public final AutofillId id;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 344b92f..8902087 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -130,9 +130,9 @@
}
FillUi(@NonNull Context context, @NonNull FillResponse response,
- @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
- @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
- @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
+ @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
mCallback = callback;
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java b/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java
new file mode 100644
index 0000000..7fbf4b9
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineContentProviderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.util.Slog;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.FgThread;
+
+/**
+ * We create one instance of this class for each {@link android.view.inputmethod.InlineSuggestion}
+ * instance. Each inline suggestion instance will only be sent to the remote IME process once. In
+ * case of filtering and resending the suggestion when keyboard state changes between hide and
+ * show, a new instance of this class will be created using {@link #copy()}, with the same backing
+ * {@link RemoteInlineSuggestionUi}. When the
+ * {@link #provideContent(int, int, IInlineContentCallback)} is called the first time (it's only
+ * allowed to be called at most once), the passed in width/height is used to determine whether
+ * the existing {@link RemoteInlineSuggestionUi} provided in the constructor can be reused, or a
+ * new one should be created to suit the new size requirement for the view. In normal cases,
+ * we should not expect the size requirement to change, although in theory the public API allows
+ * the IME to do that.
+ *
+ * <p>This design is to enable us to be able to reuse the backing remote view while still keeping
+ * the callbacks relatively well aligned. For example, if we allow multiple remote IME binder
+ * callbacks to call into one instance of this class, then binder A may call in with width/height
+ * X for which we create a view (i.e. {@link RemoteInlineSuggestionUi}) for it,
+ *
+ * See also {@link RemoteInlineSuggestionUi} for relevant information.
+ */
+final class InlineContentProviderImpl extends IInlineContentProvider.Stub {
+
+ // TODO(b/153615023): consider not holding strong reference to heavy objects in this stub, to
+ // avoid memory leak in case the client app is holding the remote reference for a longer
+ // time than expected. Essentially we need strong reference in the system process to
+ // the member variables, but weak reference to them in the IInlineContentProvider.Stub.
+
+ private static final String TAG = InlineContentProviderImpl.class.getSimpleName();
+
+ private final Handler mHandler = FgThread.getHandler();;
+
+ @NonNull
+ private final RemoteInlineSuggestionViewConnector mRemoteInlineSuggestionViewConnector;
+ @Nullable
+ private RemoteInlineSuggestionUi mRemoteInlineSuggestionUi;
+
+ private boolean mProvideContentCalled = false;
+
+ InlineContentProviderImpl(
+ @NonNull RemoteInlineSuggestionViewConnector remoteInlineSuggestionViewConnector,
+ @Nullable RemoteInlineSuggestionUi remoteInlineSuggestionUi) {
+ mRemoteInlineSuggestionViewConnector = remoteInlineSuggestionViewConnector;
+ mRemoteInlineSuggestionUi = remoteInlineSuggestionUi;
+ }
+
+ /**
+ * Returns a new instance of this class, with the same {@code mInlineSuggestionRenderer} and
+ * {@code mRemoteInlineSuggestionUi}. The latter may or may not be reusable depending on the
+ * size information provided when the client calls {@link #provideContent(int, int,
+ * IInlineContentCallback)}.
+ */
+ @NonNull
+ public InlineContentProviderImpl copy() {
+ return new InlineContentProviderImpl(mRemoteInlineSuggestionViewConnector,
+ mRemoteInlineSuggestionUi);
+ }
+
+ /**
+ * Provides a SurfacePackage associated with the inline suggestion view to the IME. If such
+ * view doesn't exit, then create a new one. This method should be called once per lifecycle
+ * of this object. Any further calls to the method will be ignored.
+ */
+ @Override
+ public void provideContent(int width, int height, IInlineContentCallback callback) {
+ mHandler.post(() -> handleProvideContent(width, height, callback));
+ }
+
+ @Override
+ public void requestSurfacePackage() {
+ mHandler.post(this::handleGetSurfacePackage);
+ }
+
+ @Override
+ public void onSurfacePackageReleased() {
+ mHandler.post(this::handleOnSurfacePackageReleased);
+ }
+
+ private void handleProvideContent(int width, int height, IInlineContentCallback callback) {
+ if (sVerbose) Slog.v(TAG, "handleProvideContent");
+ if (mProvideContentCalled) {
+ // This method should only be called once.
+ return;
+ }
+ mProvideContentCalled = true;
+ if (mRemoteInlineSuggestionUi == null || !mRemoteInlineSuggestionUi.match(width, height)) {
+ mRemoteInlineSuggestionUi = new RemoteInlineSuggestionUi(
+ mRemoteInlineSuggestionViewConnector,
+ width, height, mHandler);
+ }
+ mRemoteInlineSuggestionUi.setInlineContentCallback(callback);
+ mRemoteInlineSuggestionUi.requestSurfacePackage();
+ }
+
+ private void handleGetSurfacePackage() {
+ if (sVerbose) Slog.v(TAG, "handleGetSurfacePackage");
+ if (!mProvideContentCalled || mRemoteInlineSuggestionUi == null) {
+ // provideContent should be called first, and remote UI should not be null.
+ return;
+ }
+ mRemoteInlineSuggestionUi.requestSurfacePackage();
+ }
+
+ private void handleOnSurfacePackageReleased() {
+ if (sVerbose) Slog.v(TAG, "handleOnSurfacePackageReleased");
+ if (!mProvideContentCalled || mRemoteInlineSuggestionUi == null) {
+ // provideContent should be called first, and remote UI should not be null.
+ return;
+ }
+ mRemoteInlineSuggestionUi.surfacePackageReleased();
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
new file mode 100644
index 0000000..6522522
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.InlinePresentation;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
+
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.autofill.RemoteInlineSuggestionRenderService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+
+/**
+ * UI for a particular field (i.e. {@link AutofillId}) based on an inline autofill response from
+ * the autofill service or the augmented autofill service. It wraps multiple inline suggestions.
+ *
+ * <p> This class is responsible for filtering the suggestions based on the filtered text.
+ * It'll create {@link InlineSuggestion} instances by reusing the backing remote views (from the
+ * renderer service) if possible.
+ */
+public final class InlineFillUi {
+
+ private static final String TAG = "InlineFillUi";
+
+ /**
+ * The id of the field which the current Ui is for.
+ */
+ @NonNull
+ final AutofillId mAutofillId;
+
+ /**
+ * The list of inline suggestions, before applying any filtering
+ */
+ @NonNull
+ private final ArrayList<InlineSuggestion> mInlineSuggestions;
+
+ /**
+ * The corresponding data sets for the inline suggestions. The list may be null if the current
+ * Ui is the authentication UI for the response. If non-null, the size of data sets should equal
+ * that of inline suggestions.
+ */
+ @Nullable
+ private final ArrayList<Dataset> mDatasets;
+
+ /**
+ * The filter text which will be applied on the inline suggestion list before they are returned
+ * as a response.
+ */
+ @Nullable
+ private String mFilterText;
+
+ /**
+ * Returns an empty inline autofill UI.
+ */
+ @NonNull
+ public static InlineFillUi emptyUi(@NonNull AutofillId autofillId) {
+ return new InlineFillUi(autofillId, new SparseArray<>(), null);
+ }
+
+ /**
+ * Returns an inline autofill UI for a field based on an Autofilll response.
+ */
+ @NonNull
+ public static InlineFillUi forAutofill(@NonNull InlineSuggestionsRequest request,
+ @NonNull FillResponse response,
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull AutoFillUI.AutoFillUiCallback uiCallback,
+ @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+
+ if (InlineSuggestionFactory.responseNeedAuthentication(response)) {
+ InlineSuggestion inlineAuthentication =
+ InlineSuggestionFactory.createInlineAuthentication(request, response,
+ focusedViewId, uiCallback, onErrorCallback, remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineAuthentication, filterText);
+ } else if (response.getDatasets() != null) {
+ SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
+ InlineSuggestionFactory.createAutofillInlineSuggestions(request,
+ response.getRequestId(),
+ response.getDatasets(), focusedViewId, uiCallback, onErrorCallback,
+ remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
+ }
+ return new InlineFillUi(focusedViewId, new SparseArray<>(), filterText);
+ }
+
+ /**
+ * Returns an inline autofill UI for a field based on an Autofilll response.
+ */
+ @NonNull
+ public static InlineFillUi forAugmentedAutofill(@NonNull InlineSuggestionsRequest request,
+ @NonNull List<Dataset> datasets,
+ @NonNull AutofillId focusedViewId, @Nullable String filterText,
+ @NonNull InlineSuggestionUiCallback uiCallback,
+ @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+ SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
+ InlineSuggestionFactory.createAugmentedAutofillInlineSuggestions(request, datasets,
+ focusedViewId,
+ uiCallback, onErrorCallback, remoteRenderService);
+ return new InlineFillUi(focusedViewId, inlineSuggestions, filterText);
+ }
+
+ InlineFillUi(@NonNull AutofillId autofillId,
+ @NonNull SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions,
+ @Nullable String filterText) {
+ mAutofillId = autofillId;
+ int size = inlineSuggestions.size();
+ mDatasets = new ArrayList<>(size);
+ mInlineSuggestions = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ Pair<Dataset, InlineSuggestion> value = inlineSuggestions.valueAt(i);
+ mDatasets.add(value.first);
+ mInlineSuggestions.add(value.second);
+ }
+ mFilterText = filterText;
+ }
+
+ InlineFillUi(@NonNull AutofillId autofillId, InlineSuggestion inlineSuggestion,
+ @Nullable String filterText) {
+ mAutofillId = autofillId;
+ mDatasets = null;
+ mInlineSuggestions = new ArrayList<>();
+ mInlineSuggestions.add(inlineSuggestion);
+ mFilterText = filterText;
+ }
+
+ @NonNull
+ public AutofillId getAutofillId() {
+ return mAutofillId;
+ }
+
+ public void setFilterText(@Nullable String filterText) {
+ mFilterText = filterText;
+ }
+
+ /**
+ * Returns the list of filtered inline suggestions suitable for being sent to the IME.
+ */
+ @NonNull
+ public InlineSuggestionsResponse getInlineSuggestionsResponse() {
+ final int size = mInlineSuggestions.size();
+ if (size == 0) {
+ return new InlineSuggestionsResponse(Collections.emptyList());
+ }
+ final List<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+ if (mDatasets == null || mDatasets.size() != size) {
+ // authentication case
+ for (int i = 0; i < size; i++) {
+ inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+ for (int i = 0; i < size; i++) {
+ final Dataset dataset = mDatasets.get(i);
+ final int fieldIndex = dataset.getFieldIds().indexOf(mAutofillId);
+ if (fieldIndex < 0) {
+ Slog.w(TAG, "AutofillId=" + mAutofillId + " not found in dataset");
+ continue;
+ }
+ final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(
+ fieldIndex);
+ if (inlinePresentation == null) {
+ Slog.w(TAG, "InlinePresentation not found in dataset");
+ continue;
+ }
+ if (!inlinePresentation.isPinned() // don't filter pinned suggestions
+ && !includeDataset(dataset, fieldIndex, mFilterText)) {
+ continue;
+ }
+ inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+
+ /**
+ * Returns a copy of the suggestion, that internally copies the {@link IInlineContentProvider}
+ * so that it's not reused by the remote IME process across different inline suggestions.
+ * See {@link InlineContentProviderImpl} for why this is needed.
+ *
+ * <p>Note that although it copies the {@link IInlineContentProvider}, the underlying remote
+ * view (in the renderer service) is still reused.
+ */
+ @NonNull
+ private InlineSuggestion copy(int index, @NonNull InlineSuggestion inlineSuggestion) {
+ final IInlineContentProvider contentProvider = inlineSuggestion.getContentProvider();
+ if (contentProvider instanceof InlineContentProviderImpl) {
+ // We have to create a new inline suggestion instance to ensure we don't reuse the
+ // same {@link IInlineContentProvider}, but the underlying views are reused when
+ // calling {@link InlineContentProviderImpl#copy()}.
+ InlineSuggestion newInlineSuggestion = new InlineSuggestion(inlineSuggestion
+ .getInfo(), ((InlineContentProviderImpl) contentProvider).copy());
+ // The remote view is only set when the content provider is called to inflate the view,
+ // which happens after it's sent to the IME (i.e. not now), so we keep the latest
+ // content provider (through newInlineSuggestion) to make sure the next time we copy it,
+ // we get to reuse the view.
+ mInlineSuggestions.set(index, newInlineSuggestion);
+ return newInlineSuggestion;
+ }
+ return inlineSuggestion;
+ }
+
+ // TODO: Extract the shared filtering logic here and in FillUi to a common method.
+ private static boolean includeDataset(Dataset dataset, int fieldIndex,
+ @Nullable String filterText) {
+ // Show everything when the user input is empty.
+ if (TextUtils.isEmpty(filterText)) {
+ return true;
+ }
+
+ final String constraintLowerCase = filterText.toString().toLowerCase();
+
+ // Use the filter provided by the service, if available.
+ final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
+ if (filter != null) {
+ Pattern filterPattern = filter.pattern;
+ if (filterPattern == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
+ }
+ return true;
+ }
+ return filterPattern.matcher(constraintLowerCase).matches();
+ }
+
+ final AutofillValue value = dataset.getFieldValues().get(fieldIndex);
+ if (value == null || !value.isText()) {
+ return dataset.getAuthentication() != null;
+ }
+ final String valueText = value.getTextValue().toString().toLowerCase();
+ return valueText.toLowerCase().startsWith(constraintLowerCase);
+ }
+
+ /**
+ * Callback from the inline suggestion Ui.
+ */
+ public interface InlineSuggestionUiCallback {
+ /**
+ * Callback to autofill a dataset to the client app.
+ */
+ void autofill(@NonNull Dataset dataset);
+
+ /**
+ * Callback to start Intent in client app.
+ */
+ void startIntentSender(@NonNull IntentSender intentSender, @NonNull Intent intent);
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 79c9efa..089eeb2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -17,59 +17,57 @@
package com.android.server.autofill.ui;
import static com.android.server.autofill.Helper.sDebug;
-import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.IntentSender;
import android.os.IBinder;
-import android.os.RemoteException;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
-import android.service.autofill.IInlineSuggestionUiCallback;
import android.service.autofill.InlinePresentation;
-import android.text.TextUtils;
+import android.util.Pair;
import android.util.Slog;
-import android.view.SurfaceControlViewHost;
+import android.util.SparseArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
import android.widget.inline.InlinePresentationSpec;
-import com.android.internal.view.inline.IInlineContentCallback;
import com.android.internal.view.inline.IInlineContentProvider;
-import com.android.server.LocalServices;
-import com.android.server.UiThread;
import com.android.server.autofill.RemoteInlineSuggestionRenderService;
-import com.android.server.inputmethod.InputMethodManagerInternal;
-import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
-public final class InlineSuggestionFactory {
+final class InlineSuggestionFactory {
private static final String TAG = "InlineSuggestionFactory";
- /**
- * Callback from the inline suggestion Ui.
- */
- public interface InlineSuggestionUiCallback {
- /**
- * Callback to autofill a dataset to the client app.
- */
- void autofill(@NonNull Dataset dataset);
+ public static boolean responseNeedAuthentication(@NonNull FillResponse response) {
+ return response.getAuthentication() != null && response.getInlinePresentation() != null;
+ }
- /**
- * Callback to start Intent in client app.
- */
- void startIntentSender(@NonNull IntentSender intentSender, @NonNull Intent intent);
+ public static InlineSuggestion createInlineAuthentication(
+ @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
+ @NonNull AutofillId autofillId,
+ @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
+ final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
+ client.requestHideFillUi(autofillId);
+ client.authenticate(response.getRequestId(),
+ datasetIndex, response.getAuthentication(), response.getClientState(),
+ /* authenticateInline= */ true);
+ };
+ final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
+ client.startIntentSender(intentSender, new Intent());
+ InlinePresentation inlineAuthentication = response.getInlinePresentation();
+ return createInlineAuthSuggestion(inlineAuthentication,
+ remoteRenderService, onClickFactory, onErrorCallback, intentSenderConsumer,
+ request.getHostInputToken(), request.getHostDisplayId());
}
/**
@@ -77,33 +75,23 @@
* autofill service, potentially filtering the datasets.
*/
@Nullable
- public static InlineSuggestionsResponse createInlineSuggestionsResponse(
- @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
- @Nullable String filterText, @NonNull AutofillId autofillId,
+ public static SparseArray<Pair<Dataset, InlineSuggestion>> createAutofillInlineSuggestions(
+ @NonNull InlineSuggestionsRequest request, int requestId,
+ @NonNull List<Dataset> datasets,
+ @NonNull AutofillId autofillId,
@NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
- final BiConsumer<Dataset, Integer> onClickFactory;
- if (response.getAuthentication() != null) {
- onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
- client.authenticate(response.getRequestId(),
- datasetIndex, response.getAuthentication(), response.getClientState(),
- /* authenticateInline= */ true);
- };
- } else {
- onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
- client.fill(response.getRequestId(), datasetIndex, dataset);
- };
- }
+ final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
+ client.startIntentSender(intentSender, new Intent());
+ final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
+ client.requestHideFillUi(autofillId);
+ client.fill(requestId, datasetIndex, dataset);
+ };
- final InlinePresentation inlineAuthentication =
- response.getAuthentication() == null ? null : response.getInlinePresentation();
- return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
- response.getDatasets(), filterText, inlineAuthentication, autofillId,
- onErrorCallback, onClickFactory, (intentSender) ->
- client.startIntentSender(intentSender, new Intent()), remoteRenderService);
+ return createInlineSuggestionsInternal(/* isAugmented= */ false, request,
+ datasets, autofillId,
+ onErrorCallback, onClickFactory, intentSenderConsumer, remoteRenderService);
}
/**
@@ -111,16 +99,16 @@
* autofill service.
*/
@Nullable
- public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
+ public static SparseArray<Pair<Dataset, InlineSuggestion>>
+ createAugmentedAutofillInlineSuggestions(
@NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
@NonNull AutofillId autofillId,
- @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
+ @NonNull InlineFillUi.InlineSuggestionUiCallback inlineSuggestionUiCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
- return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
- datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
- autofillId, onErrorCallback,
+ return createInlineSuggestionsInternal(/* isAugmented= */ true, request,
+ datasets, autofillId, onErrorCallback,
(dataset, datasetIndex) ->
inlineSuggestionUiCallback.autofill(dataset),
(intentSender) ->
@@ -129,29 +117,13 @@
}
@Nullable
- private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal(
+ private static SparseArray<Pair<Dataset, InlineSuggestion>> createInlineSuggestionsInternal(
boolean isAugmented, @NonNull InlineSuggestionsRequest request,
- @Nullable List<Dataset> datasets, @Nullable String filterText,
- @Nullable InlinePresentation inlineAuthentication, @NonNull AutofillId autofillId,
+ @NonNull List<Dataset> datasets, @NonNull AutofillId autofillId,
@NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
@NonNull Consumer<IntentSender> intentSenderConsumer,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
-
- final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
- if (inlineAuthentication != null) {
- InlineSuggestion inlineAuthSuggestion = createInlineAuthSuggestion(inlineAuthentication,
- remoteRenderService, onClickFactory, onErrorCallback, intentSenderConsumer,
- request.getHostInputToken(), request.getHostDisplayId());
- inlineSuggestions.add(inlineAuthSuggestion);
-
- return new InlineSuggestionsResponse(inlineSuggestions);
- }
-
- if (datasets == null) {
- Slog.w(TAG, "Datasets should not be null here");
- return null;
- }
-
+ SparseArray<Pair<Dataset, InlineSuggestion>> response = new SparseArray<>(datasets.size());
for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
final Dataset dataset = datasets.get(datasetIndex);
final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
@@ -165,50 +137,14 @@
Slog.w(TAG, "InlinePresentation not found in dataset");
continue;
}
- if (!inlinePresentation.isPinned() // don't filter pinned suggestions
- && !includeDataset(dataset, fieldIndex, filterText)) {
- continue;
- }
InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
datasetIndex,
mergedInlinePresentation(request, datasetIndex, inlinePresentation),
onClickFactory, remoteRenderService, onErrorCallback, intentSenderConsumer,
request.getHostInputToken(), request.getHostDisplayId());
-
- inlineSuggestions.add(inlineSuggestion);
+ response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
}
- return new InlineSuggestionsResponse(inlineSuggestions);
- }
-
- // TODO: Extract the shared filtering logic here and in FillUi to a common method.
- private static boolean includeDataset(Dataset dataset, int fieldIndex,
- @Nullable String filterText) {
- // Show everything when the user input is empty.
- if (TextUtils.isEmpty(filterText)) {
- return true;
- }
-
- final String constraintLowerCase = filterText.toString().toLowerCase();
-
- // Use the filter provided by the service, if available.
- final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
- if (filter != null) {
- Pattern filterPattern = filter.pattern;
- if (filterPattern == null) {
- if (sVerbose) {
- Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
- }
- return true;
- }
- return filterPattern.matcher(constraintLowerCase).matches();
- }
-
- final AutofillValue value = dataset.getFieldValues().get(fieldIndex);
- if (value == null || !value.isText()) {
- return dataset.getAuthentication() == null;
- }
- final String valueText = value.getTextValue().toString().toLowerCase();
- return valueText.toLowerCase().startsWith(constraintLowerCase);
+ return response;
}
private static InlineSuggestion createInlineSuggestion(boolean isAugmented,
@@ -276,78 +212,20 @@
inlinePresentation.isPinned());
}
- private static IInlineContentProvider.Stub createInlineContentProvider(
+ private static IInlineContentProvider createInlineContentProvider(
@NonNull InlinePresentation inlinePresentation, @Nullable Runnable onClickAction,
@NonNull Runnable onErrorCallback,
@NonNull Consumer<IntentSender> intentSenderConsumer,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService,
@Nullable IBinder hostInputToken,
int displayId) {
- return new IInlineContentProvider.Stub() {
- @Override
- public void provideContent(int width, int height, IInlineContentCallback callback) {
- UiThread.getHandler().post(() -> {
- final IInlineSuggestionUiCallback uiCallback = createInlineSuggestionUiCallback(
- callback, onClickAction, onErrorCallback, intentSenderConsumer);
-
- if (remoteRenderService == null) {
- Slog.e(TAG, "RemoteInlineSuggestionRenderService is null");
- return;
- }
-
- remoteRenderService.renderSuggestion(uiCallback, inlinePresentation,
- width, height, hostInputToken, displayId);
- });
- }
- };
- }
-
- private static IInlineSuggestionUiCallback.Stub createInlineSuggestionUiCallback(
- @NonNull IInlineContentCallback callback, @NonNull Runnable onAutofillCallback,
- @NonNull Runnable onErrorCallback,
- @NonNull Consumer<IntentSender> intentSenderConsumer) {
- return new IInlineSuggestionUiCallback.Stub() {
- @Override
- public void onClick() throws RemoteException {
- onAutofillCallback.run();
- callback.onClick();
- }
-
- @Override
- public void onLongClick() throws RemoteException {
- callback.onLongClick();
- }
-
- @Override
- public void onContent(SurfaceControlViewHost.SurfacePackage surface, int width,
- int height)
- throws RemoteException {
- callback.onContent(surface, width, height);
- surface.release();
- }
-
- @Override
- public void onError() throws RemoteException {
- onErrorCallback.run();
- }
-
- @Override
- public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId)
- throws RemoteException {
- final InputMethodManagerInternal inputMethodManagerInternal =
- LocalServices.getService(InputMethodManagerInternal.class);
- if (!inputMethodManagerInternal.transferTouchFocusToImeWindow(sourceInputToken,
- displayId)) {
- Slog.e(TAG, "Cannot transfer touch focus from suggestion to IME");
- onErrorCallback.run();
- }
- }
-
- @Override
- public void onStartIntentSender(IntentSender intentSender) {
- intentSenderConsumer.accept(intentSender);
- }
- };
+ RemoteInlineSuggestionViewConnector
+ remoteInlineSuggestionViewConnector = new RemoteInlineSuggestionViewConnector(
+ remoteRenderService, inlinePresentation, hostInputToken, displayId, onClickAction,
+ onErrorCallback, intentSenderConsumer);
+ InlineContentProviderImpl inlineContentProvider = new InlineContentProviderImpl(
+ remoteInlineSuggestionViewConnector, null);
+ return inlineContentProvider;
}
private InlineSuggestionFactory() {
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java
new file mode 100644
index 0000000..368f717
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionUi.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.autofill.IInlineSuggestionUi;
+import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.ISurfacePackageResultCallback;
+import android.util.Slog;
+import android.view.SurfaceControlViewHost;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+
+/**
+ * The instance of this class lives in the system server, orchestrating the communication between
+ * the remote process owning embedded view (i.e. ExtServices) and the remote process hosting the
+ * embedded view (i.e. IME). It's also responsible for releasing the embedded view from the owning
+ * process when it's not longer needed in the hosting process.
+ *
+ * <p>An instance of this class may be reused to associate with multiple instances of
+ * {@link InlineContentProviderImpl}s, each of which wraps a callback from the IME. But at any
+ * given time, there is only one active IME callback which this class will callback into.
+ *
+ * <p>This class is thread safe, because all the outside calls are piped into a single handler
+ * thread to be processed.
+ */
+final class RemoteInlineSuggestionUi {
+
+ private static final String TAG = RemoteInlineSuggestionUi.class.getSimpleName();
+
+ // The delay time to release the remote inline suggestion view (in the renderer
+ // process) after receiving a signal about the surface package being released due to being
+ // detached from the window in the host app (in the IME process). The release will be
+ // canceled if the host app reattaches the view to a window within this delay time.
+ // TODO(b/154683107): try out using the Chroreographer to schedule the release right at the
+ // next frame. Basically if the view is not re-attached to the window immediately in the next
+ // frame after it was detached, then it will be released.
+ private static final long RELEASE_REMOTE_VIEW_HOST_DELAY_MS = 200;
+
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final RemoteInlineSuggestionViewConnector mRemoteInlineSuggestionViewConnector;
+ private final int mWidth;
+ private final int mHeight;
+ @NonNull
+ private final InlineSuggestionUiCallbackImpl mInlineSuggestionUiCallback;
+
+ @Nullable
+ private IInlineContentCallback mInlineContentCallback; // from IME
+
+ /**
+ * Remote inline suggestion view, backed by an instance of {@link SurfaceControlViewHost} in
+ * the render service process. We takes care of releasing it when there is no remote
+ * reference to it (from IME), and we will create a new instance of the view when it's needed
+ * by IME again.
+ */
+ @Nullable
+ private IInlineSuggestionUi mInlineSuggestionUi;
+ private int mRefCount = 0;
+ private boolean mWaitingForUiCreation = false;
+ private int mActualWidth;
+ private int mActualHeight;
+
+ @Nullable
+ private Runnable mDelayedReleaseViewRunnable;
+
+ RemoteInlineSuggestionUi(
+ @NonNull RemoteInlineSuggestionViewConnector remoteInlineSuggestionViewConnector,
+ int width, int height, Handler handler) {
+ mHandler = handler;
+ mRemoteInlineSuggestionViewConnector = remoteInlineSuggestionViewConnector;
+ mWidth = width;
+ mHeight = height;
+ mInlineSuggestionUiCallback = new InlineSuggestionUiCallbackImpl();
+ }
+
+ /**
+ * Updates the callback from the IME process. It'll swap out the previous IME callback, and
+ * all the subsequent callback events (onClick, onLongClick, touch event transfer, etc) will
+ * be directed to the new callback.
+ */
+ void setInlineContentCallback(@NonNull IInlineContentCallback inlineContentCallback) {
+ mHandler.post(() -> {
+ mInlineContentCallback = inlineContentCallback;
+ });
+ }
+
+ /**
+ * Handles the request from the IME process to get a new surface package. May create a new
+ * view in the renderer process if the existing view is already released.
+ */
+ void requestSurfacePackage() {
+ mHandler.post(this::handleRequestSurfacePackage);
+ }
+
+ /**
+ * Handles the signal from the IME process that the previously sent surface package has been
+ * released.
+ */
+ void surfacePackageReleased() {
+ mHandler.post(() -> handleUpdateRefCount(-1));
+ }
+
+ /**
+ * Returns true if the provided size matches the remote view's size.
+ */
+ boolean match(int width, int height) {
+ return mWidth == width && mHeight == height;
+ }
+
+ private void handleRequestSurfacePackage() {
+ cancelPendingReleaseViewRequest();
+
+ if (mInlineSuggestionUi == null) {
+ if (mWaitingForUiCreation) {
+ // This could happen in the following case: the remote embedded view was released
+ // when previously detached from window. An event after that to re-attached to
+ // the window will cause us calling the renderSuggestion again. Now, before the
+ // render call returns a new surface package, if the view is detached and
+ // re-attached to the window, causing this method to be called again, we will get
+ // to this state. This request will be ignored and the surface package will still
+ // be sent back once the view is rendered.
+ if (sDebug) Slog.d(TAG, "Inline suggestion ui is not ready");
+ } else {
+ mRemoteInlineSuggestionViewConnector.renderSuggestion(mWidth, mHeight,
+ mInlineSuggestionUiCallback);
+ mWaitingForUiCreation = true;
+ }
+ } else {
+ try {
+ mInlineSuggestionUi.getSurfacePackage(new ISurfacePackageResultCallback.Stub() {
+ @Override
+ public void onResult(SurfaceControlViewHost.SurfacePackage result) {
+ mHandler.post(() -> {
+ if (sVerbose) Slog.v(TAG, "Sending refreshed SurfacePackage to IME");
+ try {
+ mInlineContentCallback.onContent(result, mActualWidth,
+ mActualHeight);
+ handleUpdateRefCount(1);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onContent");
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling getSurfacePackage.");
+ }
+ }
+ }
+
+ private void handleUpdateRefCount(int delta) {
+ cancelPendingReleaseViewRequest();
+ mRefCount += delta;
+ if (mRefCount <= 0) {
+ mDelayedReleaseViewRunnable = () -> {
+ if (mInlineSuggestionUi != null) {
+ try {
+ if (sVerbose) Slog.v(TAG, "releasing the host");
+ mInlineSuggestionUi.releaseSurfaceControlViewHost();
+ mInlineSuggestionUi = null;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling releaseSurfaceControlViewHost");
+ }
+ }
+ mDelayedReleaseViewRunnable = null;
+ };
+ mHandler.postDelayed(mDelayedReleaseViewRunnable, RELEASE_REMOTE_VIEW_HOST_DELAY_MS);
+ }
+ }
+
+ private void cancelPendingReleaseViewRequest() {
+ if (mDelayedReleaseViewRunnable != null) {
+ mHandler.removeCallbacks(mDelayedReleaseViewRunnable);
+ mDelayedReleaseViewRunnable = null;
+ }
+ }
+
+ /**
+ * This is called when a new inline suggestion UI is inflated from the ext services.
+ */
+ private void handleInlineSuggestionUiReady(IInlineSuggestionUi content,
+ SurfaceControlViewHost.SurfacePackage surfacePackage, int width, int height) {
+ mInlineSuggestionUi = content;
+ mRefCount = 0;
+ mWaitingForUiCreation = false;
+ mActualWidth = width;
+ mActualHeight = height;
+ if (mInlineContentCallback != null) {
+ try {
+ if (sVerbose) Slog.v(TAG, "Sending new UI content to IME");
+ handleUpdateRefCount(1);
+ mInlineContentCallback.onContent(surfacePackage, mActualWidth, mActualHeight);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onContent");
+ }
+ }
+ if (surfacePackage != null) {
+ surfacePackage.release();
+ }
+ }
+
+ private void handleOnClick() {
+ // Autofill the value
+ mRemoteInlineSuggestionViewConnector.onClick();
+
+ // Notify the remote process (IME) that hosts the embedded UI that it's clicked
+ if (mInlineContentCallback != null) {
+ try {
+ mInlineContentCallback.onClick();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onClick");
+ }
+ }
+ }
+
+ private void handleOnLongClick() {
+ // Notify the remote process (IME) that hosts the embedded UI that it's long clicked
+ if (mInlineContentCallback != null) {
+ try {
+ mInlineContentCallback.onLongClick();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onLongClick");
+ }
+ }
+ }
+
+ private void handleOnError() {
+ mRemoteInlineSuggestionViewConnector.onError();
+ }
+
+ private void handleOnTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ mRemoteInlineSuggestionViewConnector.onTransferTouchFocusToImeWindow(sourceInputToken,
+ displayId);
+ }
+
+ private void handleOnStartIntentSender(IntentSender intentSender) {
+ mRemoteInlineSuggestionViewConnector.onStartIntentSender(intentSender);
+ }
+
+ /**
+ * Responsible for communicating with the inline suggestion view owning process.
+ */
+ private class InlineSuggestionUiCallbackImpl extends IInlineSuggestionUiCallback.Stub {
+
+ @Override
+ public void onClick() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnClick);
+ }
+
+ @Override
+ public void onLongClick() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnLongClick);
+ }
+
+ @Override
+ public void onContent(IInlineSuggestionUi content,
+ SurfaceControlViewHost.SurfacePackage surface, int width, int height) {
+ mHandler.post(() -> handleInlineSuggestionUiReady(content, surface, width, height));
+ }
+
+ @Override
+ public void onError() {
+ mHandler.post(RemoteInlineSuggestionUi.this::handleOnError);
+ }
+
+ @Override
+ public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ mHandler.post(() -> handleOnTransferTouchFocusToImeWindow(sourceInputToken, displayId));
+ }
+
+ @Override
+ public void onStartIntentSender(IntentSender intentSender) {
+ mHandler.post(() -> handleOnStartIntentSender(intentSender));
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
new file mode 100644
index 0000000..9d23c17
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.IBinder;
+import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.InlinePresentation;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.autofill.RemoteInlineSuggestionRenderService;
+import com.android.server.inputmethod.InputMethodManagerInternal;
+
+import java.util.function.Consumer;
+
+/**
+ * Wraps the parameters needed to create a new inline suggestion view in the remote renderer
+ * service, and handles the callback from the events on the created remote view.
+ */
+final class RemoteInlineSuggestionViewConnector {
+ private static final String TAG = RemoteInlineSuggestionViewConnector.class.getSimpleName();
+
+ @Nullable
+ private final RemoteInlineSuggestionRenderService mRemoteRenderService;
+ @NonNull
+ private final InlinePresentation mInlinePresentation;
+ @Nullable
+ private final IBinder mHostInputToken;
+ private final int mDisplayId;
+
+ @NonNull
+ private final Runnable mOnAutofillCallback;
+ @NonNull
+ private final Runnable mOnErrorCallback;
+ @NonNull
+ private final Consumer<IntentSender> mStartIntentSenderFromClientApp;
+
+ RemoteInlineSuggestionViewConnector(
+ @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
+ @NonNull InlinePresentation inlinePresentation,
+ @Nullable IBinder hostInputToken,
+ int displayId,
+ @NonNull Runnable onAutofillCallback,
+ @NonNull Runnable onErrorCallback,
+ @NonNull Consumer<IntentSender> startIntentSenderFromClientApp) {
+ mRemoteRenderService = remoteRenderService;
+ mInlinePresentation = inlinePresentation;
+ mHostInputToken = hostInputToken;
+ mDisplayId = displayId;
+
+ mOnAutofillCallback = onAutofillCallback;
+ mOnErrorCallback = onErrorCallback;
+ mStartIntentSenderFromClientApp = startIntentSenderFromClientApp;
+ }
+
+ /**
+ * Calls the remote renderer service to create a new inline suggestion view.
+ *
+ * @return true if the call is made to the remote renderer service, false otherwise.
+ */
+ public boolean renderSuggestion(int width, int height,
+ @NonNull IInlineSuggestionUiCallback callback) {
+ if (mRemoteRenderService != null) {
+ if (sDebug) Slog.d(TAG, "Request to recreate the UI");
+ mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
+ mHostInputToken, mDisplayId);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Handles the callback for the event of remote view being clicked.
+ */
+ public void onClick() {
+ mOnAutofillCallback.run();
+ }
+
+ /**
+ * Handles the callback for the remote error when creating or interacting with the view.
+ */
+ public void onError() {
+ mOnErrorCallback.run();
+ }
+
+ /**
+ * Handles the callback for transferring the touch event on the remote view to the IME
+ * process.
+ */
+ public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
+ final InputMethodManagerInternal inputMethodManagerInternal =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ if (!inputMethodManagerInternal.transferTouchFocusToImeWindow(sourceInputToken,
+ displayId)) {
+ Slog.e(TAG, "Cannot transfer touch focus from suggestion to IME");
+ mOnErrorCallback.run();
+ }
+ }
+
+ /**
+ * Handles starting an intent sender from the client app's process.
+ */
+ public void onStartIntentSender(IntentSender intentSender) {
+ mStartIntentSenderFromClientApp.accept(intentSender);
+ }
+}
diff --git a/services/backup/Android.bp b/services/backup/Android.bp
index f02da20..56b788e 100644
--- a/services/backup/Android.bp
+++ b/services/backup/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.backup",
+ defaults: ["services_defaults"],
srcs: [":services.backup-sources"],
libs: ["services.core"],
static_libs: ["backuplib"],
diff --git a/services/companion/Android.bp b/services/companion/Android.bp
index 9677a7d..e251042 100644
--- a/services/companion/Android.bp
+++ b/services/companion/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.companion",
+ defaults: ["services_defaults"],
srcs: [":services.companion-sources"],
libs: ["services.core"],
}
diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp
index 96e2072..7006430 100644
--- a/services/contentcapture/Android.bp
+++ b/services/contentcapture/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.contentcapture",
+ defaults: ["services_defaults"],
srcs: [":services.contentcapture-sources"],
libs: ["services.core"],
}
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
index d17f06f..3fe3cd2 100644
--- a/services/contentsuggestions/Android.bp
+++ b/services/contentsuggestions/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.contentsuggestions",
+ defaults: ["services_defaults"],
srcs: [":services.contentsuggestions-sources"],
libs: ["services.core"],
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 77773ed..cf85b1d 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -127,9 +127,10 @@
"android.hardware.soundtrigger-V2.3-java",
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
- "dnsresolver_aidl_interface-V4-java",
- "netd_event_listener_interface-java",
+ "dnsresolver_aidl_interface-java",
+ "netd_aidl_interfaces-platform-java",
"overlayable_policy_aidl-java",
+ "SurfaceFlingerProperties",
],
}
@@ -148,6 +149,7 @@
java_library {
name: "services.core",
+ defaults: ["services_defaults"],
static_libs: ["services.core.priorityboosted"],
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e4eb585..2c63c6f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3011,10 +3011,13 @@
// Legacy version of notifyNetworkTestedWithExtras.
// Would only be called if the system has a NetworkStack module older than the
// framework, which does not happen in practice.
+ Slog.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
}
@Override
public void notifyNetworkTestedWithExtras(NetworkTestResultParcelable p) {
+ // Notify mTrackerHandler and mConnectivityDiagnosticsHandler of the event. Both use
+ // the same looper so messages will be processed in sequence.
final Message msg = mTrackerHandler.obtainMessage(
EVENT_NETWORK_TESTED,
new NetworkTestedResults(
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index bfcde97..829fca6 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -253,10 +253,7 @@
logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
} catch (Throwable t) {
- final String msg = ExceptionUtils.getCompleteMessage(t);
- EventLogTags.writeRescueFailure(level, msg);
- logCriticalInfo(Log.ERROR,
- "Failed rescue level " + levelToString(level) + ": " + msg);
+ logRescueException(level, t);
}
}
@@ -274,11 +271,31 @@
resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
break;
case LEVEL_FACTORY_RESET:
- RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
+ // when device shutting down.
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ } catch (Throwable t) {
+ logRescueException(level, t);
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
break;
}
}
+ private static void logRescueException(int level, Throwable t) {
+ final String msg = ExceptionUtils.getCompleteMessage(t);
+ EventLogTags.writeRescueFailure(level, msg);
+ logCriticalInfo(Log.ERROR,
+ "Failed rescue level " + levelToString(level) + ": " + msg);
+ }
+
private static int mapRescueLevelToUserImpact(int rescueLevel) {
switch(rescueLevel) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index cfb79aa..b1b5ec0 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -169,7 +169,11 @@
@Override
public String toString() {
- return component.toShortString() + "@" + version + "[u" + userId + "]";
+ if (component == null) {
+ return "none";
+ } else {
+ return component.toShortString() + "@" + version + "[u" + userId + "]";
+ }
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 14fe0c5..be53945 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1579,6 +1579,14 @@
writeSettingsLocked();
}
}
+
+ if (newState == VolumeInfo.STATE_MOUNTED) {
+ // Private volumes can be unmounted and re-mounted even after a user has
+ // been unlocked; on devices that support encryption keys tied to the filesystem,
+ // this requires setting up the keys again.
+ prepareUserStorageIfNeeded(vol);
+ }
+
// This is a blocking call to Storage Service which needs to process volume state changed
// before notifying other listeners.
// Intentionally called without the mLock to avoid deadlocking from the Storage Service.
@@ -3266,10 +3274,38 @@
}
}
+ private void prepareUserStorageIfNeeded(VolumeInfo vol) {
+ if (vol.type != VolumeInfo.TYPE_PRIVATE) {
+ return;
+ }
+
+ final UserManager um = mContext.getSystemService(UserManager.class);
+ final UserManagerInternal umInternal =
+ LocalServices.getService(UserManagerInternal.class);
+
+ for (UserInfo user : um.getUsers(false /* includeDying */)) {
+ final int flags;
+ if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
+ } else if (umInternal.isUserRunning(user.id)) {
+ flags = StorageManager.FLAG_STORAGE_DE;
+ } else {
+ continue;
+ }
+
+ prepareUserStorageInternal(vol.fsUuid, user.id, user.serialNumber, flags);
+ }
+ }
+
@Override
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ prepareUserStorageInternal(volumeUuid, userId, serialNumber, flags);
+ }
+
+ private void prepareUserStorageInternal(String volumeUuid, int userId, int serialNumber,
+ int flags) {
try {
mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
// After preparing user storage, we should check if we should mount data mirror again,
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index b09d741..26cb208 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -450,6 +450,14 @@
return oldNightMode != mNightMode;
}
+ private static long toMilliSeconds(LocalTime t) {
+ return t.toNanoOfDay() / 1000;
+ }
+
+ private static LocalTime fromMilliseconds(long t) {
+ return LocalTime.ofNanoOfDay(t * 1000);
+ }
+
private void registerScreenOffEventLocked() {
if (mPowerSave) return;
mWaitForScreenOff = true;
@@ -777,6 +785,7 @@
pw.print(" ");
}
pw.println("");
+ pw.print(" waitScreenOff="); pw.print(mWaitForScreenOff);
pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
pw.print(" customStart="); pw.print(mCustomAutoNightModeStartMilliseconds);
pw.print(" customEnd"); pw.print(mCustomAutoNightModeEndMilliseconds);
@@ -1384,8 +1393,11 @@
pw.println("UiModeManager service (uimode) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" night [yes|no|auto]");
+ pw.println(" night [yes|no|auto|custom]");
pw.println(" Set or read night mode.");
+ pw.println(" time [start|end] <ISO time>");
+ pw.println(" Set custom start/end schedule time"
+ + " (night mode must be set to custom to apply).");
}
@Override
@@ -1398,6 +1410,8 @@
switch (cmd) {
case "night":
return handleNightMode();
+ case "time":
+ return handleCustomTime();
default:
return handleDefaultCommands(cmd);
}
@@ -1408,6 +1422,34 @@
return -1;
}
+ private int handleCustomTime() throws RemoteException {
+ final String modeStr = getNextArg();
+ if (modeStr == null) {
+ printCustomTime();
+ return 0;
+ }
+ switch (modeStr) {
+ case "start":
+ final String start = getNextArg();
+ mInterface.setCustomNightModeStart(toMilliSeconds(LocalTime.parse(start)));
+ return 0;
+ case "end":
+ final String end = getNextArg();
+ mInterface.setCustomNightModeEnd(toMilliSeconds(LocalTime.parse(end)));
+ return 0;
+ default:
+ getErrPrintWriter().println("command must be in [start|end]");
+ return -1;
+ }
+ }
+
+ private void printCustomTime() throws RemoteException {
+ getOutPrintWriter().println("start " + fromMilliseconds(
+ mInterface.getCustomNightModeStart()).toString());
+ getOutPrintWriter().println("end " + fromMilliseconds(
+ mInterface.getCustomNightModeEnd()).toString());
+ }
+
private int handleNightMode() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
final String modeStr = getNextArg();
@@ -1423,7 +1465,8 @@
return 0;
} else {
err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
- + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO + "'");
+ + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
+ + "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
return -1;
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 419389f..cca6046 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1634,22 +1634,24 @@
new AppOpsManager.OnOpNotedListener() {
@Override
public void onOpNoted(int op, int uid, String pkgName, int result) {
- if (uid == mProcessRecord.uid && isNotTop()) {
- incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED);
- }
+ incrementOpCountIfNeeded(op, uid, result);
}
};
- private final AppOpsManager.OnOpActiveChangedInternalListener mOpActiveCallback =
- new AppOpsManager.OnOpActiveChangedInternalListener() {
+ private final AppOpsManager.OnOpStartedListener mOpStartedCallback =
+ new AppOpsManager.OnOpStartedListener() {
@Override
- public void onOpActiveChanged(int op, int uid, String pkgName, boolean active) {
- if (uid == mProcessRecord.uid && active && isNotTop()) {
- incrementOpCount(op, true);
- }
+ public void onOpStarted(int op, int uid, String pkgName, int result) {
+ incrementOpCountIfNeeded(op, uid, result);
}
};
+ private void incrementOpCountIfNeeded(int op, int uid, @AppOpsManager.Mode int result) {
+ if (uid == mProcessRecord.uid && isNotTop()) {
+ incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED);
+ }
+ }
+
private boolean isNotTop() {
return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP;
}
@@ -1674,7 +1676,7 @@
mNumFgs++;
if (mNumFgs == 1) {
mAppOpsManager.startWatchingNoted(LOGGED_AP_OPS, mOpNotedCallback);
- mAppOpsManager.startWatchingActive(LOGGED_AP_OPS, mOpActiveCallback);
+ mAppOpsManager.startWatchingStarted(LOGGED_AP_OPS, mOpStartedCallback);
}
}
@@ -1684,7 +1686,7 @@
mDestroyed = true;
logFinalValues();
mAppOpsManager.stopWatchingNoted(mOpNotedCallback);
- mAppOpsManager.stopWatchingActive(mOpActiveCallback);
+ mAppOpsManager.stopWatchingStarted(mOpStartedCallback);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 6b917bc..4ff421e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -367,6 +367,15 @@
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
+ /**
+ * The threshold to decide if a given association should be dumped into metrics.
+ */
+ private static final long DEFAULT_MIN_ASSOC_LOG_DURATION = 5 * 60 * 1000; // 5 mins
+
+ private static final String KEY_MIN_ASSOC_LOG_DURATION = "min_assoc_log_duration";
+
+ public static long MIN_ASSOC_LOG_DURATION = DEFAULT_MIN_ASSOC_LOG_DURATION;
+
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -395,6 +404,9 @@
case KEY_FORCE_BACKGROUND_CHECK_ON_RESTRICTED_APPS:
updateForceRestrictedBackgroundCheck();
break;
+ case KEY_MIN_ASSOC_LOG_DURATION:
+ updateMinAssocLogDuration();
+ break;
default:
break;
}
@@ -659,6 +671,12 @@
CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3;
}
+ private void updateMinAssocLogDuration() {
+ MIN_ASSOC_LOG_DURATION = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MIN_ASSOC_LOG_DURATION,
+ /* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -729,6 +747,8 @@
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
+ pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
+ pw.println(MIN_ASSOC_LOG_DURATION);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0bd134c..d914bda 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8766,27 +8766,6 @@
}
@Override
- public boolean isUidActiveOrForeground(int uid, String callingPackage) {
- if (!hasUsageStatsPermission(callingPackage)) {
- enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
- "isUidActiveOrForeground");
- }
- synchronized (this) {
- final boolean isActive = isUidActiveLocked(uid);
- if (isActive) {
- return true;
- }
- }
- final boolean isForeground = mAtmInternal.isUidForeground(uid);
- if (isForeground) {
- Slog.wtf(TAG, "isUidActiveOrForeground: isUidActive false but "
- + " isUidForeground true, uid:" + uid
- + " callingPackage:" + callingPackage);
- }
- return isForeground;
- }
-
- @Override
public void setPersistentVrThread(int tid) {
mActivityTaskManager.setPersistentVrThread(tid);
}
@@ -10535,12 +10514,14 @@
}
mAtmInternal.dump(
DUMP_STARTER_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
+ if (dumpPackage == null) {
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ mAtmInternal.dump(
+ DUMP_CONTAINERS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
}
- mAtmInternal.dump(
- DUMP_CONTAINERS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
// Activities section is dumped as part of the Critical priority dump. Exclude the
// section if priority is Normal.
if (!dumpNormalPriority) {
@@ -10558,6 +10539,11 @@
}
dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
}
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
if (dumpPackage == null) {
pw.println();
if (dumpAll) {
@@ -10574,17 +10560,6 @@
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpLruLocked(pw, dumpPackage);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
- mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------"
- + "------------");
- }
dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
pw.println();
if (dumpAll) {
@@ -10788,7 +10763,7 @@
}
} else if ("oom".equals(cmd) || "o".equals(cmd)) {
synchronized (this) {
- dumpOomLocked(fd, pw, args, opti, true);
+ dumpOomLocked(fd, pw, false, args, opti, true, dumpPackage, true);
}
} else if ("lmk".equals(cmd)) {
synchronized (this) {
@@ -10796,11 +10771,11 @@
}
} else if ("lru".equals(cmd)) {
synchronized (this) {
- dumpLruLocked(pw, null);
+ dumpLruLocked(pw, dumpPackage, null);
}
} else if ("permissions".equals(cmd) || "perm".equals(cmd)) {
synchronized (this) {
- dumpPermissionsLocked(fd, pw, args, opti, true, null);
+ dumpPermissionsLocked(fd, pw, args, opti, true, dumpPackage);
}
} else if ("provider".equals(cmd)) {
String[] newArgs;
@@ -10820,7 +10795,7 @@
}
} else if ("providers".equals(cmd) || "prov".equals(cmd)) {
synchronized (this) {
- dumpProvidersLocked(fd, pw, args, opti, true, null);
+ dumpProvidersLocked(fd, pw, args, opti, true, dumpPackage);
}
} else if ("service".equals(cmd)) {
String[] newArgs;
@@ -11106,8 +11081,9 @@
" Counts of Binder Proxies held by SYSTEM");
}
- void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc) {
- pw.print(" #");
+ void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc, String prefix) {
+ pw.print(prefix);
+ pw.print("#");
pw.print(index);
pw.print(": ");
pw.print(ProcessList.makeOomAdjString(proc.setAdj, false));
@@ -11149,9 +11125,29 @@
}
// TODO: Move to ProcessList?
- void dumpLruLocked(PrintWriter pw, String dumpPackage) {
- pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)");
+ boolean dumpLruLocked(PrintWriter pw, String dumpPackage, String prefix) {
final int N = mProcessList.mLruProcesses.size();
+ final String innerPrefix;
+ if (prefix == null) {
+ pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)");
+ innerPrefix = " ";
+ } else {
+ boolean haveAny = false;
+ for (int i = N - 1; i >= 0; i--) {
+ final ProcessRecord r = mProcessList.mLruProcesses.get(i);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ haveAny = true;
+ break;
+ }
+ if (!haveAny) {
+ return false;
+ }
+ pw.print(prefix);
+ pw.println("Raw LRU list (dumpsys activity lru):");
+ innerPrefix = prefix + " ";
+ }
int i;
boolean first = true;
for (i = N - 1; i >= mProcessList.mLruProcessActivityStart; i--) {
@@ -11160,10 +11156,11 @@
continue;
}
if (first) {
- pw.println(" Activities:");
+ pw.print(innerPrefix);
+ pw.println("Activities:");
first = false;
}
- dumpLruEntryLocked(pw, i, r);
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
}
first = true;
for (; i >= mProcessList.mLruProcessServiceStart; i--) {
@@ -11172,10 +11169,11 @@
continue;
}
if (first) {
- pw.println(" Services:");
+ pw.print(innerPrefix);
+ pw.println("Services:");
first = false;
}
- dumpLruEntryLocked(pw, i, r);
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
}
first = true;
for (; i >= 0; i--) {
@@ -11184,11 +11182,13 @@
continue;
}
if (first) {
- pw.println(" Other:");
+ pw.print(innerPrefix);
+ pw.println("Other:");
first = false;
}
- dumpLruEntryLocked(pw, i, r);
+ dumpLruEntryLocked(pw, i, r, innerPrefix);
}
+ return true;
}
// TODO: Move to ProcessList?
@@ -11200,7 +11200,7 @@
pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
- if (dumpAll) {
+ if (dumpAll || dumpPackage != null) {
final int NP = mProcessList.mProcessNames.getMap().size();
for (int ip=0; ip<NP; ip++) {
SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip);
@@ -11267,6 +11267,12 @@
}
}
+ if (dumpOomLocked(fd, pw, needSep, args, opti, dumpAll, dumpPackage, false)) {
+ needSep = true;
+ }
+
+ needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
+
if (mProcessList.mActiveUids.size() > 0) {
if (dumpUids(pw, dumpPackage, dumpAppId, mProcessList.mActiveUids,
"UID states:", needSep)) {
@@ -11283,6 +11289,13 @@
}
}
+ if (needSep) {
+ pw.println();
+ }
+ if (dumpLruLocked(pw, dumpPackage, " ")) {
+ needSep = true;
+ }
+
if (mProcessList.getLruSizeLocked() > 0) {
if (needSep) {
pw.println();
@@ -11387,8 +11400,6 @@
"OnHold Norm", "OnHold PERS", dumpPackage);
}
- needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
-
needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
needSep = mAtmInternal.dumpForProcesses(fd, pw, dumpAll, dumpPackage, dumpAppId, needSep,
@@ -11931,10 +11942,8 @@
pw.println(")");
}
- boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll) {
- boolean needSep = false;
-
+ boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, boolean inclGc) {
if (mProcessList.getLruSizeLocked() > 0) {
if (needSep) pw.println();
needSep = true;
@@ -11965,11 +11974,11 @@
- mProcessList.mLruProcessServiceStart);
pw.println("):");
dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", true,
- null);
+ dumpPackage);
needSep = true;
}
- dumpProcessesToGc(pw, needSep, null);
+ dumpProcessesToGc(pw, needSep, dumpPackage);
pw.println();
mAtmInternal.dumpForOom(pw);
@@ -20171,4 +20180,15 @@
mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken);
}
}
+
+ @Override
+ public boolean isAppFreezerSupported() {
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ return mOomAdjuster.mCachedAppOptimizer.isFreezerSupported();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 0c3d02d..02fb34e 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -785,7 +785,7 @@
}
void dumpHistoryProcessExitInfo(PrintWriter pw, String packageName) {
- pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity exit-info)");
+ pw.println("ACTIVITY MANAGER PROCESS EXIT INFO (dumpsys activity exit-info)");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
synchronized (mLock) {
pw.println("Last Timestamp of Persistence Into Persistent Storage: "
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 86d9028..f9d204f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -33,6 +33,7 @@
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -407,7 +408,7 @@
/**
* Determines whether the freezer is correctly supported by this system
*/
- public boolean isFreezerSupported() {
+ public static boolean isFreezerSupported() {
boolean supported = false;
FileReader fr = null;
@@ -443,7 +444,13 @@
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseFreezer() {
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ final String configOverride = Settings.Global.getString(mAm.mContext.getContentResolver(),
+ Settings.Global.CACHED_APPS_FREEZER_ENABLED);
+
+ if ("disabled".equals(configOverride)) {
+ mUseFreezer = false;
+ } else if ("enabled".equals(configOverride)
+ || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index e869e57..b753de9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -120,6 +120,7 @@
import com.android.server.Watchdog;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowManagerService;
@@ -2169,7 +2170,12 @@
Map<String, Pair<String, Long>> result = new ArrayMap<>(packages.length);
int userId = UserHandle.getUserId(uid);
for (String packageName : packages) {
- String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
+ AndroidPackage androidPackage = pmInt.getPackage(packageName);
+ if (androidPackage == null) {
+ Slog.w(TAG, "Unknown package:" + packageName);
+ continue;
+ }
+ String volumeUuid = androidPackage.getVolumeUuid();
long inode = pmInt.getCeDataInode(packageName, userId);
if (inode == 0) {
Slog.w(TAG, packageName + " inode == 0 (b/152760674)");
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 6d4a9f4..a034949 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -617,6 +617,14 @@
return newHighWaterMark;
}
+ /**
+ * @return The threshold to decide if a given association should be dumped into metrics.
+ */
+ @Override
+ public long getMinAssociationDumpDuration() {
+ return mAm.mConstants.MIN_ASSOC_LOG_DURATION;
+ }
+
private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
throws IOException {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 3dbf2c6..16d83ec 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -116,6 +116,7 @@
viewMessage = res.getString(R.string.user_switching_message, mNewUser.name);
}
}
+ view.setAccessibilityPaneTitle(viewMessage);
((TextView) view.findViewById(R.id.message)).setText(viewMessage);
setView(view);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index de9b02f..63e01e0 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -149,6 +149,7 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsNotedCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IAppOpsStartedCallback;
import com.android.internal.app.MessageSamplingConfig;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
@@ -1292,6 +1293,7 @@
final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
+ final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
@@ -1407,6 +1409,50 @@
}
}
+ final class StartedCallback implements DeathRecipient {
+ final IAppOpsStartedCallback mCallback;
+ final int mWatchingUid;
+ final int mCallingUid;
+ final int mCallingPid;
+
+ StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid,
+ int callingPid) {
+ mCallback = callback;
+ mWatchingUid = watchingUid;
+ mCallingUid = callingUid;
+ mCallingPid = callingPid;
+ try {
+ mCallback.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ /*ignored*/
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("StartedCallback{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" watchinguid=");
+ UserHandle.formatUid(sb, mWatchingUid);
+ sb.append(" from uid=");
+ UserHandle.formatUid(sb, mCallingUid);
+ sb.append(" pid=");
+ sb.append(mCallingPid);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ void destroy() {
+ mCallback.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ stopWatchingStarted(mCallback);
+ }
+ }
+
final class NotedCallback implements DeathRecipient {
final IAppOpsNotedCallback mCallback;
final int mWatchingUid;
@@ -2545,11 +2591,11 @@
if (callbacks == null) {
callbacks = new HashMap<>();
}
- boolean duplicate = false;
final int N = cbs.size();
for (int i=0; i<N; i++) {
ModeCallback cb = cbs.valueAt(i);
ArrayList<ChangeRec> reports = callbacks.get(cb);
+ boolean duplicate = false;
if (reports == null) {
reports = new ArrayList<>();
callbacks.put(cb, reports);
@@ -3031,13 +3077,12 @@
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
- final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
}
- final UidState uidState = ops.uidState;
+ final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
if (attributedOp.isRunning()) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+ code + " startTime of in progress event="
@@ -3045,6 +3090,7 @@
}
final int switchCode = AppOpsManager.opToSwitch(code);
+ final UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
@@ -3076,10 +3122,9 @@
+ packageName + (attributionTag == null ? ""
: "." + attributionTag));
}
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
flags);
- scheduleOpNotedIfNeededLocked(code, uid, packageName,
- AppOpsManager.MODE_ALLOWED);
if (shouldCollectAsyncNotedOp) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
@@ -3092,7 +3137,7 @@
// TODO moltmann: Allow watching for attribution ops
@Override
public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
- int watchedUid = -1;
+ int watchedUid = Process.INVALID_UID;
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
@@ -3139,6 +3184,54 @@
}
@Override
+ public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
+ int watchedUid = Process.INVALID_UID;
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+ != PackageManager.PERMISSION_GRANTED) {
+ watchedUid = callingUid;
+ }
+
+ Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
+ Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
+ "Invalid op code in: " + Arrays.toString(ops));
+ Objects.requireNonNull(callback, "Callback cannot be null");
+
+ synchronized (this) {
+ SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
+ if (callbacks == null) {
+ callbacks = new SparseArray<>();
+ mStartedWatchers.put(callback.asBinder(), callbacks);
+ }
+
+ final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
+ callingUid, callingPid);
+ for (int op : ops) {
+ callbacks.put(op, startedCallback);
+ }
+ }
+ }
+
+ @Override
+ public void stopWatchingStarted(IAppOpsStartedCallback callback) {
+ Objects.requireNonNull(callback, "Callback cannot be null");
+
+ synchronized (this) {
+ final SparseArray<StartedCallback> startedCallbacks =
+ mStartedWatchers.remove(callback.asBinder());
+ if (startedCallbacks == null) {
+ return;
+ }
+
+ final int callbackCount = startedCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ startedCallbacks.valueAt(i).destroy();
+ }
+ }
+ }
+
+ @Override
public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
int watchedUid = Process.INVALID_UID;
final int callingUid = Binder.getCallingUid();
@@ -3340,12 +3433,14 @@
final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass,
true /* edit */);
if (ops == null) {
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
}
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
@@ -3353,7 +3448,6 @@
final UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
- final int opCode = op.op;
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED
@@ -3362,6 +3456,7 @@
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, uidMode);
return uidMode;
}
} else {
@@ -3374,11 +3469,13 @@
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, mode);
return mode;
}
}
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+ " package " + resolvedPackageName);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
try {
attributedOp.started(clientId, uidState.state);
} catch (RemoteException e) {
@@ -3480,6 +3577,52 @@
}
}
+ private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, int result) {
+ ArraySet<StartedCallback> dispatchedCallbacks = null;
+ final int callbackListCount = mStartedWatchers.size();
+ for (int i = 0; i < callbackListCount; i++) {
+ final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
+
+ StartedCallback callback = callbacks.get(code);
+ if (callback != null) {
+ if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+ continue;
+ }
+
+ if (dispatchedCallbacks == null) {
+ dispatchedCallbacks = new ArraySet<>();
+ }
+ dispatchedCallbacks.add(callback);
+ }
+ }
+
+ if (dispatchedCallbacks == null) {
+ return;
+ }
+
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ AppOpsService::notifyOpStarted,
+ this, dispatchedCallbacks, code, uid, pkgName, result));
+ }
+
+ private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
+ int code, int uid, String packageName, int result) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int callbackCount = callbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final StartedCallback callback = callbacks.valueAt(i);
+ try {
+ callback.mCallback.opStarted(code, uid, packageName, result);
+ } catch (RemoteException e) {
+ /* do nothing */
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
int result) {
ArraySet<NotedCallback> dispatchedCallbacks = null;
@@ -5185,6 +5328,56 @@
pw.println(cb);
}
}
+ if (mStartedWatchers.size() > 0 && dumpMode < 0) {
+ needSep = true;
+ boolean printedHeader = false;
+
+ final int watchersSize = mStartedWatchers.size();
+ for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
+ final SparseArray<StartedCallback> startedWatchers =
+ mStartedWatchers.valueAt(watcherNum);
+ if (startedWatchers.size() <= 0) {
+ continue;
+ }
+
+ final StartedCallback cb = startedWatchers.valueAt(0);
+ if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
+ continue;
+ }
+
+ if (dumpPackage != null
+ && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+ continue;
+ }
+
+ if (!printedHeader) {
+ pw.println(" All op started watchers:");
+ printedHeader = true;
+ }
+
+ pw.print(" ");
+ pw.print(Integer.toHexString(System.identityHashCode(
+ mStartedWatchers.keyAt(watcherNum))));
+ pw.println(" ->");
+
+ pw.print(" [");
+ final int opCount = startedWatchers.size();
+ for (int opNum = 0; opNum < opCount; opNum++) {
+ if (opNum > 0) {
+ pw.print(' ');
+ }
+
+ pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
+ if (opNum < opCount - 1) {
+ pw.print(',');
+ }
+ }
+ pw.println("]");
+
+ pw.print(" ");
+ pw.println(cb);
+ }
+ }
if (mNotedWatchers.size() > 0 && dumpMode < 0) {
needSep = true;
boolean printedHeader = false;
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 604b9f1..9cd9039 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -37,7 +37,12 @@
]
},
{
- "name": "CtsAppTestCases:ActivityManagerApi29Test"
+ "name": "CtsAppTestCases",
+ "options": [
+ {
+ "include-filter": "android.app.cts.ActivityManagerApi29Test"
+ }
+ ]
},
{
"name": "UidAtomTests:testAppOps"
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7cac376..17baead 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1217,6 +1217,8 @@
*/
@NonNull
public List<AudioProductStrategy> getAudioProductStrategies() {
+ // verify permissions
+ enforceModifyAudioRoutingPermission();
return AudioProductStrategy.getAudioProductStrategies();
}
@@ -1226,6 +1228,8 @@
*/
@NonNull
public List<AudioVolumeGroup> getAudioVolumeGroups() {
+ // verify permissions
+ enforceModifyAudioRoutingPermission();
return AudioVolumeGroup.getAudioVolumeGroups();
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 70fbca5..7e28e94 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -170,6 +170,8 @@
final String mOpPackageName;
// Info to be shown on BiometricDialog when all cookies are returned.
final Bundle mBundle;
+ // Random id associated to this AuthSession
+ final int mSysUiSessionId;
final int mCallingUid;
final int mCallingPid;
final int mCallingUserId;
@@ -203,11 +205,13 @@
mClientReceiver = receiver;
mOpPackageName = opPackageName;
mBundle = bundle;
+ mSysUiSessionId = mRandom.nextInt();
mCallingUid = callingUid;
mCallingPid = callingPid;
mCallingUserId = callingUserId;
mModality = modality;
mRequireConfirmation = requireConfirmation;
+ Slog.d(TAG, "New AuthSession, mSysUiSessionId: " + mSysUiSessionId);
}
boolean isCrypto() {
@@ -1457,7 +1461,8 @@
false /* requireConfirmation */,
mCurrentAuthSession.mUserId,
mCurrentAuthSession.mOpPackageName,
- mCurrentAuthSession.mSessionId);
+ mCurrentAuthSession.mSessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} else {
mPendingAuthSession.mClientReceiver.onError(modality, error, vendorCode);
mPendingAuthSession = null;
@@ -1680,7 +1685,8 @@
mStatusBarService.showAuthenticationDialog(mCurrentAuthSession.mBundle,
mInternalReceiver, modality, requireConfirmation, userId,
mCurrentAuthSession.mOpPackageName,
- mCurrentAuthSession.mSessionId);
+ mCurrentAuthSession.mSessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -1766,7 +1772,8 @@
false /* requireConfirmation */,
mCurrentAuthSession.mUserId,
mCurrentAuthSession.mOpPackageName,
- sessionId);
+ sessionId,
+ mCurrentAuthSession.mSysUiSessionId);
} else {
mPendingAuthSession.mState = STATE_AUTH_CALLED;
for (AuthenticatorWrapper authenticator : mAuthenticators) {
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index 5010e46..3e61920 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -50,6 +50,7 @@
private SignalStrength mSignalStrength;
private ServiceState mServiceState;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+ private int mNrState = NetworkRegistrationInfo.NR_STATE_NONE;
public DataConnectionStats(Context context, Handler listenerHandler) {
mContext = context;
@@ -99,6 +100,11 @@
mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
int networkType = regInfo == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN
: regInfo.getAccessNetworkTechnology();
+ // If the device is in NSA NR connection the networkType will report as LTE.
+ // For cell dwell rate metrics, this should report NR instead.
+ if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+ networkType = TelephonyManager.NETWORK_TYPE_NR;
+ }
if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
networkType, visible ? "" : "not "));
try {
@@ -153,6 +159,7 @@
@Override
public void onServiceStateChanged(ServiceState state) {
mServiceState = state;
+ mNrState = state.getNrState();
notePhoneDataConnectionState();
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 228966c..103f659 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -17,7 +17,6 @@
package com.android.server.connectivity;
import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP;
import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
@@ -85,6 +84,12 @@
public class VpnIkev2Utils {
private static final String TAG = VpnIkev2Utils.class.getSimpleName();
+ // TODO: Use IKE library exposed constants when @SystemApi is updated.
+ /** IANA-defined 3072 group for use in IKEv2 */
+ private static final int DH_GROUP_3072_BIT_MODP = 15;
+ /** IANA-defined 4096 group for use in IKEv2 */
+ private static final int DH_GROUP_4096_BIT_MODP = 16;
+
static IkeSessionParams buildIkeSessionParams(
@NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
@@ -177,8 +182,9 @@
// Add dh, prf for both builders
for (final IkeSaProposal.Builder builder : Arrays.asList(normalModeBuilder, aeadBuilder)) {
+ builder.addDhGroup(DH_GROUP_4096_BIT_MODP);
+ builder.addDhGroup(DH_GROUP_3072_BIT_MODP);
builder.addDhGroup(DH_GROUP_2048_BIT_MODP);
- builder.addDhGroup(DH_GROUP_1024_BIT_MODP);
builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC);
builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 4a1afb2..041bedc 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1819,7 +1819,8 @@
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.sync_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
- new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
+ new Intent(Settings.ACTION_SYNC_SETTINGS), PendingIntent.FLAG_IMMUTABLE, null,
+ UserHandle.of(userId)));
return intent;
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 612fd39..c54ebf8 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -152,6 +152,47 @@
return votes;
}
+ private static final class VoteSummary {
+ public float minRefreshRate;
+ public float maxRefreshRate;
+ public int width;
+ public int height;
+
+ VoteSummary() {
+ reset();
+ }
+
+ public void reset() {
+ minRefreshRate = 0f;
+ maxRefreshRate = Float.POSITIVE_INFINITY;
+ width = Vote.INVALID_SIZE;
+ height = Vote.INVALID_SIZE;
+ }
+ }
+
+ // VoteSummary is returned as an output param to cut down a bit on the number of temporary
+ // objects.
+ private void summarizeVotes(
+ SparseArray<Vote> votes, int lowestConsideredPriority, /*out*/ VoteSummary summary) {
+ summary.reset();
+ for (int priority = Vote.MAX_PRIORITY; priority >= lowestConsideredPriority; priority--) {
+ Vote vote = votes.get(priority);
+ if (vote == null) {
+ continue;
+ }
+ // For refresh rates, just use the tightest bounds of all the votes
+ summary.minRefreshRate = Math.max(summary.minRefreshRate, vote.refreshRateRange.min);
+ summary.maxRefreshRate = Math.min(summary.maxRefreshRate, vote.refreshRateRange.max);
+ // For display size, use only the first vote we come across (i.e. the highest
+ // priority vote that includes the width / height).
+ if (summary.height == Vote.INVALID_SIZE && summary.width == Vote.INVALID_SIZE
+ && vote.height > 0 && vote.width > 0) {
+ summary.width = vote.width;
+ summary.height = vote.height;
+ }
+ }
+ }
+
/**
* Calculates the refresh rate ranges and display modes that the system is allowed to freely
* switch between based on global and display-specific constraints.
@@ -174,52 +215,31 @@
}
int[] availableModes = new int[]{defaultMode.getModeId()};
- float minRefreshRate = 0f;
- float maxRefreshRate = Float.POSITIVE_INFINITY;
+ VoteSummary primarySummary = new VoteSummary();
int lowestConsideredPriority = Vote.MIN_PRIORITY;
while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
- minRefreshRate = 0f;
- maxRefreshRate = Float.POSITIVE_INFINITY;
- int height = Vote.INVALID_SIZE;
- int width = Vote.INVALID_SIZE;
-
- for (int priority = Vote.MAX_PRIORITY;
- priority >= lowestConsideredPriority; priority--) {
- Vote vote = votes.get(priority);
- if (vote == null) {
- continue;
- }
- // For refresh rates, just use the tightest bounds of all the votes
- minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
- maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
- // For display size, use only the first vote we come across (i.e. the highest
- // priority vote that includes the width / height).
- if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
- && vote.height > 0 && vote.width > 0) {
- width = vote.width;
- height = vote.height;
- }
- }
+ summarizeVotes(votes, lowestConsideredPriority, primarySummary);
// If we don't have anything specifying the width / height of the display, just use
// the default width and height. We don't want these switching out from underneath
// us since it's a pretty disruptive behavior.
- if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
- width = defaultMode.getPhysicalWidth();
- height = defaultMode.getPhysicalHeight();
+ if (primarySummary.height == Vote.INVALID_SIZE
+ || primarySummary.width == Vote.INVALID_SIZE) {
+ primarySummary.width = defaultMode.getPhysicalWidth();
+ primarySummary.height = defaultMode.getPhysicalHeight();
}
- availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+ availableModes = filterModes(modes, primarySummary);
if (availableModes.length > 0) {
if (DEBUG) {
Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+ " with lowest priority considered "
+ Vote.priorityToString(lowestConsideredPriority)
+ " and constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
+ + "width=" + primarySummary.width
+ + ", height=" + primarySummary.height
+ + ", minRefreshRate=" + primarySummary.minRefreshRate
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
}
break;
}
@@ -228,10 +248,10 @@
Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
+ Vote.priorityToString(lowestConsideredPriority)
+ " and with the following constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
+ + "width=" + primarySummary.width
+ + ", height=" + primarySummary.height
+ + ", minRefreshRate=" + primarySummary.minRefreshRate
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
}
// If we haven't found anything with the current set of votes, drop the
@@ -239,6 +259,20 @@
lowestConsideredPriority++;
}
+ VoteSummary appRequestSummary = new VoteSummary();
+ summarizeVotes(
+ votes, Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, appRequestSummary);
+ appRequestSummary.minRefreshRate =
+ Math.min(appRequestSummary.minRefreshRate, primarySummary.minRefreshRate);
+ appRequestSummary.maxRefreshRate =
+ Math.max(appRequestSummary.maxRefreshRate, primarySummary.maxRefreshRate);
+ if (DEBUG) {
+ Slog.i(TAG,
+ String.format("App request range: [%.0f %.0f]",
+ appRequestSummary.minRefreshRate,
+ appRequestSummary.maxRefreshRate));
+ }
+
int baseModeId = defaultMode.getModeId();
if (availableModes.length > 0) {
baseModeId = availableModes[0];
@@ -246,20 +280,23 @@
// filterModes function is going to filter the modes based on the voting system. If
// the application requests a given mode with preferredModeId function, it will be
// stored as baseModeId.
- return new DesiredDisplayModeSpecs(
- baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
+ return new DesiredDisplayModeSpecs(baseModeId,
+ new RefreshRateRange(
+ primarySummary.minRefreshRate, primarySummary.maxRefreshRate),
+ new RefreshRateRange(
+ appRequestSummary.minRefreshRate, appRequestSummary.maxRefreshRate));
}
}
- private int[] filterModes(Display.Mode[] supportedModes,
- int width, int height, float minRefreshRate, float maxRefreshRate) {
+ private int[] filterModes(Display.Mode[] supportedModes, VoteSummary summary) {
ArrayList<Display.Mode> availableModes = new ArrayList<>();
for (Display.Mode mode : supportedModes) {
- if (mode.getPhysicalWidth() != width || mode.getPhysicalHeight() != height) {
+ if (mode.getPhysicalWidth() != summary.width
+ || mode.getPhysicalHeight() != summary.height) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId() + ", wrong size"
- + ": desiredWidth=" + width
- + ": desiredHeight=" + height
+ + ": desiredWidth=" + summary.width
+ + ": desiredHeight=" + summary.height
+ ": actualWidth=" + mode.getPhysicalWidth()
+ ": actualHeight=" + mode.getPhysicalHeight());
}
@@ -269,13 +306,13 @@
// Some refresh rates are calculated based on frame timings, so they aren't *exactly*
// equal to expected refresh rate. Given that, we apply a bit of tolerance to this
// comparison.
- if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
- || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
+ if (refreshRate < (summary.minRefreshRate - FLOAT_TOLERANCE)
+ || refreshRate > (summary.maxRefreshRate + FLOAT_TOLERANCE)) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ ", outside refresh rate bounds"
- + ": minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate
+ + ": minRefreshRate=" + summary.minRefreshRate
+ + ", maxRefreshRate=" + summary.maxRefreshRate
+ ", modeRefreshRate=" + refreshRate);
}
continue;
@@ -535,7 +572,7 @@
/**
* Information about the desired display mode to be set by the system. Includes the base
- * mode ID and refresh rate range.
+ * mode ID and the primary and app request refresh rate ranges.
*
* We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
* distinction between the config ID / physical index that
@@ -548,17 +585,28 @@
*/
public int baseModeId;
/**
- * The refresh rate range.
+ * The primary refresh rate range.
*/
- public final RefreshRateRange refreshRateRange;
+ public final RefreshRateRange primaryRefreshRateRange;
+ /**
+ * The app request refresh rate range. Lower priority considerations won't be included in
+ * this range, allowing surface flinger to consider additional refresh rates for apps that
+ * call setFrameRate(). This range will be greater than or equal to the primary refresh rate
+ * range, never smaller.
+ */
+ public final RefreshRateRange appRequestRefreshRateRange;
public DesiredDisplayModeSpecs() {
- refreshRateRange = new RefreshRateRange();
+ primaryRefreshRateRange = new RefreshRateRange();
+ appRequestRefreshRateRange = new RefreshRateRange();
}
- public DesiredDisplayModeSpecs(int baseModeId, @NonNull RefreshRateRange refreshRateRange) {
+ public DesiredDisplayModeSpecs(int baseModeId,
+ @NonNull RefreshRateRange primaryRefreshRateRange,
+ @NonNull RefreshRateRange appRequestRefreshRateRange) {
this.baseModeId = baseModeId;
- this.refreshRateRange = refreshRateRange;
+ this.primaryRefreshRateRange = primaryRefreshRateRange;
+ this.appRequestRefreshRateRange = appRequestRefreshRateRange;
}
/**
@@ -566,8 +614,10 @@
*/
@Override
public String toString() {
- return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId,
- refreshRateRange.min, refreshRateRange.max);
+ return String.format("baseModeId=%d primaryRefreshRateRange=[%.0f %.0f]"
+ + " appRequestRefreshRateRange=[%.0f %.0f]",
+ baseModeId, primaryRefreshRateRange.min, primaryRefreshRateRange.max,
+ appRequestRefreshRateRange.min, appRequestRefreshRateRange.max);
}
/**
* Checks whether the two objects have the same values.
@@ -587,7 +637,11 @@
if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
return false;
}
- if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) {
+ if (!primaryRefreshRateRange.equals(desiredDisplayModeSpecs.primaryRefreshRateRange)) {
+ return false;
+ }
+ if (!appRequestRefreshRateRange.equals(
+ desiredDisplayModeSpecs.appRequestRefreshRateRange)) {
return false;
}
return true;
@@ -595,7 +649,7 @@
@Override
public int hashCode() {
- return Objects.hash(baseModeId, refreshRateRange);
+ return Objects.hash(baseModeId, primaryRefreshRateRange, appRequestRefreshRateRange);
}
/**
@@ -603,8 +657,10 @@
*/
public void copyFrom(DesiredDisplayModeSpecs other) {
baseModeId = other.baseModeId;
- refreshRateRange.min = other.refreshRateRange.min;
- refreshRateRange.max = other.refreshRateRange.max;
+ primaryRefreshRateRange.min = other.primaryRefreshRateRange.min;
+ primaryRefreshRateRange.max = other.primaryRefreshRateRange.max;
+ appRequestRefreshRateRange.min = other.appRequestRefreshRateRange.min;
+ appRequestRefreshRateRange.max = other.appRequestRefreshRateRange.max;
}
}
@@ -637,12 +693,17 @@
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
public static final int PRIORITY_LOW_POWER_MODE = 5;
- // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as
- // appropriate, as well as priorityToString.
+ // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
+ // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
+ // The cutoff for the app request refresh rate range. Votes with priorities lower than this
+ // value will not be considered when constructing the app request refresh rate range.
+ public static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
+ PRIORITY_APP_REQUEST_REFRESH_RATE;
+
/**
* A value signifying an invalid width or height in a vote.
*/
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index bafeb77..9411c562 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1067,12 +1067,22 @@
mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f;
final boolean brightnessIsTemporary =
mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
- if (initialRampSkip || hasBrightnessBuckets
- || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
- animateScreenBrightness(brightnessState, SCREEN_ANIMATION_RATE_MINIMUM);
- } else {
- animateScreenBrightness(brightnessState,
- slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
+ // We only want to animate the brightness if it is between 0.0f and 1.0f.
+ // brightnessState can contain the values -1.0f and NaN, which we do not want to
+ // animate to. To avoid this, we check the value first.
+ // If the brightnessState is off (-1.0f) we still want to animate to the minimum
+ // brightness (0.0f) to accommodate for LED displays, which can appear bright to the
+ // user even when the display is all black.
+ float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
+ ? PowerManager.BRIGHTNESS_MIN : brightnessState;
+ if (isValidBrightnessValue(animateValue)) {
+ if (initialRampSkip || hasBrightnessBuckets
+ || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
+ animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
+ } else {
+ animateScreenBrightness(animateValue,
+ slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
+ }
}
if (!brightnessIsTemporary) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 24e1b4e..4b6430d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -146,7 +146,7 @@
/**
* Sets the display brightness.
*
- * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
+ * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest).
*/
public void setScreenBrightness(float brightness) {
if (mScreenBrightness != brightness) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 6132467..4f5a02a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -310,9 +310,14 @@
// list of available modes will take care of updating display config specs.
if (activeBaseMode != NO_DISPLAY_MODE_ID) {
if (mDisplayModeSpecs.baseModeId != activeBaseMode
- || mDisplayModeSpecs.refreshRateRange.min != configSpecs.minRefreshRate
- || mDisplayModeSpecs.refreshRateRange.max
- != configSpecs.maxRefreshRate) {
+ || mDisplayModeSpecs.primaryRefreshRateRange.min
+ != configSpecs.primaryRefreshRateMin
+ || mDisplayModeSpecs.primaryRefreshRateRange.max
+ != configSpecs.primaryRefreshRateMax
+ || mDisplayModeSpecs.appRequestRefreshRateRange.min
+ != configSpecs.appRequestRefreshRateMin
+ || mDisplayModeSpecs.appRequestRefreshRateRange.max
+ != configSpecs.appRequestRefreshRateMax) {
mDisplayModeSpecsInvalid = true;
sendTraversalRequestLocked();
}
@@ -799,8 +804,10 @@
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId,
- mDisplayModeSpecs.refreshRateRange.min,
- mDisplayModeSpecs.refreshRateRange.max)));
+ mDisplayModeSpecs.primaryRefreshRateRange.min,
+ mDisplayModeSpecs.primaryRefreshRateRange.max,
+ mDisplayModeSpecs.appRequestRefreshRateRange.min,
+ mDisplayModeSpecs.appRequestRefreshRateRange.max)));
}
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 2cae1d6..905a10b 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -571,7 +571,7 @@
// APK signatures is already verified elsewhere in PackageManager. We do not need to
// verify it again since it could cause a timeout for large APKs.
pkg.setSigningDetails(
- ParsingPackageUtils.collectCertificates(pkg, /* skipVerify= */ true));
+ ParsingPackageUtils.getSigningDetails(pkg, /* skipVerify= */ true));
return PackageInfoUtils.generate(
pkg,
null,
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 4f8708a..ccbe96f 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -69,6 +69,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
@@ -2600,6 +2601,14 @@
}
@Override
+ public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
+ ParcelFileDescriptor err, String[] args) {
+ return new LocationShellCommand(this).exec(
+ this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
+ args);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
return;
@@ -2658,8 +2667,7 @@
mRequestStatistics.statistics);
for (Map.Entry<PackageProviderKey, PackageStatistics> entry
: sorted.entrySet()) {
- PackageProviderKey key = entry.getKey();
- ipw.println(key.mPackageName + ": " + key.mProviderName + ": " + entry.getValue());
+ ipw.println(entry.getKey() + ": " + entry.getValue());
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index dcdf48b..e629b42 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.util.Log;
@@ -25,6 +26,7 @@
import com.android.internal.util.IndentingPrintWriter;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Objects;
@@ -121,14 +123,30 @@
this.mProviderName = providerName;
}
+ @NonNull
+ @Override
+ public String toString() {
+ return mProviderName + ": " + mPackageName
+ + (mFeatureId == null ? "" : ": " + mFeatureId);
+ }
+
+ /**
+ * Sort by provider, then package, then feature
+ */
@Override
public int compareTo(PackageProviderKey other) {
final int providerCompare = mProviderName.compareTo(other.mProviderName);
if (providerCompare != 0) {
return providerCompare;
- } else {
- return mProviderName.compareTo(other.mProviderName);
}
+
+ final int packageCompare = mPackageName.compareTo(other.mPackageName);
+ if (packageCompare != 0) {
+ return packageCompare;
+ }
+
+ return Objects.compare(mFeatureId, other.mFeatureId, Comparator
+ .nullsFirst(String::compareTo));
}
@Override
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
new file mode 100644
index 0000000..909873f
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.os.BasicShellCommandHandler;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Interprets and executes 'adb shell cmd location [args]'.
+ */
+class LocationShellCommand extends BasicShellCommandHandler {
+
+ private final LocationManagerService mService;
+
+ LocationShellCommand(LocationManagerService service) {
+ mService = Objects.requireNonNull(service);
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+
+ switch (cmd) {
+ case "set-location-enabled": {
+ int userId = parseUserId();
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ mService.setLocationEnabledForUser(enabled, userId);
+ return 0;
+ }
+ case "send-extra-command": {
+ String provider = getNextArgRequired();
+ String command = getNextArgRequired();
+ mService.sendExtraCommand(provider, command, null);
+ return 0;
+ }
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int parseUserId() {
+ final String option = getNextOption();
+ if (option != null) {
+ if (option.equals("--user")) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException(
+ "Expected \"--user\" option, but got \"" + option + "\" instead");
+ }
+ }
+
+ return UserHandle.USER_CURRENT_OR_SELF;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Location service commands:");
+ pw.println(" help or -h");
+ pw.println(" Print this help text.");
+ pw.println(" set-location-enabled [--user <USER_ID>] true|false");
+ pw.println(" Sets the master location switch enabled state.");
+ pw.println(" send-extra-command <PROVIDER> <COMMAND>");
+ pw.println(" Sends the given extra command to the given provider.");
+ pw.println();
+ pw.println(" Common commands that may be supported by the gps provider, depending on");
+ pw.println(" hardware and software configurations:");
+ pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
+ pw.println(" force_time_injection - requests NTP time injection to chipset");
+ pw.println(" force_psds_injection - "
+ + "requests predictive aiding data injection to chipset");
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7972f24..ac982dd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1972,7 +1972,13 @@
public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
long challenge, int userId) {
checkPasswordReadPermission(userId);
- return doVerifyCredential(credential, CHALLENGE_FROM_CALLER, challenge, userId,
+ @ChallengeType int challengeType = CHALLENGE_FROM_CALLER;
+ if (challenge == 0) {
+ Slog.w(TAG, "VerifyCredential called with challenge=0");
+ challengeType = CHALLENGE_NONE;
+
+ }
+ return doVerifyCredential(credential, challengeType, challenge, userId,
null /* progressCallback */);
}
@@ -3441,6 +3447,11 @@
public boolean armRebootEscrow() {
return mRebootEscrowManager.armRebootEscrowIfNeeded();
}
+
+ @Override
+ public void refreshStrongAuthTimeout(int userId) {
+ mStrongAuth.refreshStrongAuthTimeout(userId);
+ }
}
private class RebootEscrowCallbacks implements RebootEscrowManager.Callbacks {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 8480197..a102406 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -58,6 +58,7 @@
private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
private static final int MSG_STRONG_BIOMETRIC_UNLOCK = 8;
private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT = 9;
+ private static final int MSG_REFRESH_STRONG_AUTH_TIMEOUT = 10;
@VisibleForTesting
protected static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
@@ -143,6 +144,15 @@
public long getNextAlarmTimeMs(long timeout) {
return SystemClock.elapsedRealtime() + timeout;
}
+
+ /**
+ * Wraps around {@link SystemClock#elapsedRealtime}, which returns the number of
+ * milliseconds since boot, including time spent in sleep.
+ */
+ @VisibleForTesting
+ public long getElapsedRealtimeMs() {
+ return SystemClock.elapsedRealtime();
+ }
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -231,22 +241,33 @@
}
}
- private void handleScheduleStrongAuthTimeout(int userId) {
+ /**
+ * Re-schedule the strong auth timeout alarm with latest information on the most recent
+ * successful strong auth time and strong auth timeout from device policy.
+ */
+ private void rescheduleStrongAuthTimeoutAlarm(long strongAuthTime, int userId) {
final DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- long nextAlarmTime =
- mInjector.getNextAlarmTimeMs(dpm.getRequiredStrongAuthTimeout(null, userId));
// cancel current alarm listener for the user (if there was one)
StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
if (alarm != null) {
mAlarmManager.cancel(alarm);
+ alarm.setLatestStrongAuthTime(strongAuthTime);
} else {
- alarm = new StrongAuthTimeoutAlarmListener(userId);
+ alarm = new StrongAuthTimeoutAlarmListener(strongAuthTime, userId);
mStrongAuthTimeoutAlarmListenerForUser.put(userId, alarm);
}
+ // AlarmManager.set() correctly handles the case where nextAlarmTime has already been in
+ // the past (by firing the listener straight away), so nothing special for us to do here.
+ long nextAlarmTime = strongAuthTime + dpm.getRequiredStrongAuthTimeout(null, userId);
+
// schedule a new alarm listener for the user
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmTime,
STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm, mHandler);
+ }
+
+ private void handleScheduleStrongAuthTimeout(int userId) {
+ rescheduleStrongAuthTimeoutAlarm(mInjector.getElapsedRealtimeMs(), userId);
// cancel current non-strong biometric alarm listener for the user (if there was one)
cancelNonStrongBiometricAlarmListener(userId);
@@ -256,6 +277,13 @@
setIsNonStrongBiometricAllowed(true, userId);
}
+ private void handleRefreshStrongAuthTimeout(int userId) {
+ StrongAuthTimeoutAlarmListener alarm = mStrongAuthTimeoutAlarmListenerForUser.get(userId);
+ if (alarm != null) {
+ rescheduleStrongAuthTimeoutAlarm(alarm.getLatestStrongAuthTime(), userId);
+ }
+ }
+
private void handleScheduleNonStrongBiometricTimeout(int userId) {
if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricTimeout for userId=" + userId);
long nextAlarmTime = mInjector.getNextAlarmTimeMs(DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS);
@@ -456,6 +484,13 @@
}
/**
+ * Refreshes pending strong auth timeout with the latest admin requirement set by device policy.
+ */
+ public void refreshStrongAuthTimeout(int userId) {
+ mHandler.obtainMessage(MSG_REFRESH_STRONG_AUTH_TIMEOUT, userId, 0).sendToTarget();
+ }
+
+ /**
* Report successful unlocking with biometric
*/
public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
@@ -489,12 +524,30 @@
@VisibleForTesting
protected class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
+ private long mLatestStrongAuthTime;
private final int mUserId;
- public StrongAuthTimeoutAlarmListener(int userId) {
+ public StrongAuthTimeoutAlarmListener(long latestStrongAuthTime, int userId) {
+ mLatestStrongAuthTime = latestStrongAuthTime;
mUserId = userId;
}
+ /**
+ * Sets the most recent time when a successful strong auth happened, in number of
+ * milliseconds.
+ */
+ public void setLatestStrongAuthTime(long strongAuthTime) {
+ mLatestStrongAuthTime = strongAuthTime;
+ }
+
+ /**
+ * Returns the most recent time when a successful strong auth happened, in number of
+ * milliseconds.
+ */
+ public long getLatestStrongAuthTime() {
+ return mLatestStrongAuthTime;
+ }
+
@Override
public void onAlarm() {
requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
@@ -558,6 +611,9 @@
case MSG_SCHEDULE_STRONG_AUTH_TIMEOUT:
handleScheduleStrongAuthTimeout(msg.arg1);
break;
+ case MSG_REFRESH_STRONG_AUTH_TIMEOUT:
+ handleRefreshStrongAuthTimeout(msg.arg1);
+ break;
case MSG_NO_LONGER_REQUIRE_STRONG_AUTH:
handleNoLongerRequireStrongAuth(msg.arg1, msg.arg2);
break;
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 3cf22c8..54958d3 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -29,6 +29,7 @@
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -210,7 +211,11 @@
newBtRoute.btDevice = device;
// Current / Max volume will be set when connected.
// TODO: Is there any BT device which has fixed volume?
- newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), device.getName())
+ String deviceName = device.getName();
+ if (TextUtils.isEmpty(deviceName)) {
+ deviceName = mContext.getResources().getText(R.string.unknownName).toString();
+ }
+ newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), deviceName)
.addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
.setDescription(mContext.getResources().getText(
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index a5de90c..a435f1e 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -315,9 +315,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean duplicateSessionAlreadyExists = false;
synchronized (mLock) {
@@ -348,9 +346,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean found = false;
synchronized (mLock) {
@@ -380,9 +376,7 @@
return;
}
- sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
- .setProviderId(getUniqueId())
- .build();
+ sessionInfo = updateSessionInfo(sessionInfo);
boolean found = false;
synchronized (mLock) {
@@ -403,6 +397,13 @@
mCallback.onSessionReleased(this, sessionInfo);
}
+ private RoutingSessionInfo updateSessionInfo(RoutingSessionInfo sessionInfo) {
+ return new RoutingSessionInfo.Builder(sessionInfo)
+ .setOwnerPackageName(mComponentName.getPackageName())
+ .setProviderId(getUniqueId())
+ .build();
+ }
+
private void onRequestFailed(Connection connection, long requestId, int reason) {
if (mActiveConnection != connection) {
return;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ec941c8..3283fd9b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -799,7 +799,6 @@
writePolicyAL();
}
- enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true);
setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service");
updateRulesForGlobalChangeAL(false);
updateNotificationsNL();
@@ -871,6 +870,9 @@
new NetworkRequest.Builder().build(), mNetworkCallback);
mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
+ synchronized (mUidRulesFirstLock) {
+ updateRulesForAppIdleParoleUL();
+ }
// Listen for subscriber changes
mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
@@ -3893,6 +3895,39 @@
}
/**
+ * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
+ * changed.
+ */
+ @GuardedBy("mUidRulesFirstLock")
+ private void updateRulesForAppIdleParoleUL() {
+ final boolean paroled = mAppStandby.isInParole();
+ final boolean enableChain = !paroled;
+ enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
+
+ int ruleCount = mUidFirewallStandbyRules.size();
+ for (int i = 0; i < ruleCount; i++) {
+ final int uid = mUidFirewallStandbyRules.keyAt(i);
+ int oldRules = mUidRules.get(uid);
+ if (enableChain) {
+ // Chain wasn't enabled before and the other power-related
+ // chains are whitelists, so we can clear the
+ // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
+ // the effective rules result in blocking network access.
+ oldRules &= MASK_METERED_NETWORKS;
+ } else {
+ // Skip if it had no restrictions to begin with
+ if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+ }
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ if (newUidRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, newUidRules);
+ }
+ }
+ }
+
+ /**
* Update rules that might be changed by {@link #mRestrictBackground},
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
*/
@@ -4347,7 +4382,7 @@
private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules);
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
@@ -4361,28 +4396,30 @@
*
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
+ * @param paroled whether to ignore idle state of apps and only look at other restrictions
*
* @return the new computed rules for the uid
*/
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules) {
+ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
- "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules);
+ "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
+ + (paroled ? "P" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules);
+ return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules) {
+ private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
if (!isUidValidForBlacklistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE;
}
- final boolean isIdle = isUidIdle(uid);
+ final boolean isIdle = !paroled && isUidIdle(uid);
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
@@ -4452,6 +4489,14 @@
} catch (NameNotFoundException nnfe) {
}
}
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ synchronized (mUidRulesFirstLock) {
+ mLogger.paroleStateChanged(isParoleOn);
+ updateRulesForAppIdleParoleUL();
+ }
+ }
}
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 1951fc0..adf0176 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -178,6 +178,9 @@
// Perform polling, persist network, and register the global alert again.
private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
private static final int MSG_UPDATE_IFACES = 3;
+ // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent
+ // deadlock.
+ private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4;
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -386,6 +389,13 @@
registerGlobalAlert();
break;
}
+ case MSG_BROADCAST_NETWORK_STATS_UPDATED: {
+ final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
+ updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
+ READ_NETWORK_USAGE_HISTORY);
+ break;
+ }
}
}
}
@@ -1513,10 +1523,7 @@
}
// finally, dispatch updated event to any listeners
- final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
- updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
- READ_NETWORK_USAGE_HISTORY);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
Trace.traceEnd(TRACE_TAG_NETWORK);
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index fad0a7d..a604625 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -98,6 +98,7 @@
private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
protected static final String ENABLED_SERVICES_SEPARATOR = ":";
private static final String DB_VERSION_1 = "1";
+ private static final String DB_VERSION_2 = "2";
/**
@@ -110,7 +111,7 @@
static final String ATT_VERSION = "version";
static final String ATT_DEFAULTS = "defaults";
- static final int DB_VERSION = 2;
+ static final int DB_VERSION = 3;
static final int APPROVAL_BY_PACKAGE = 0;
static final int APPROVAL_BY_COMPONENT = 1;
@@ -571,14 +572,16 @@
}
}
}
- boolean isVersionOne = TextUtils.isEmpty(version) || DB_VERSION_1.equals(version);
- if (isVersionOne) {
- upgradeToVersionTwo();
+ boolean isOldVersion = TextUtils.isEmpty(version)
+ || DB_VERSION_1.equals(version)
+ || DB_VERSION_2.equals(version);
+ if (isOldVersion) {
+ upgradeDefaultsXmlVersion();
}
rebindServices(false, USER_ALL);
}
- private void upgradeToVersionTwo() {
+ private void upgradeDefaultsXmlVersion() {
// check if any defaults are loaded
int defaultsSize = mDefaultComponents.size() + mDefaultPackages.size();
if (defaultsSize == 0) {
@@ -1312,7 +1315,7 @@
intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
final PendingIntent pendingIntent = PendingIntent.getActivity(
- mContext, 0, new Intent(mConfig.settingsAction), 0);
+ mContext, 0, new Intent(mConfig.settingsAction), PendingIntent.FLAG_IMMUTABLE);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
ApplicationInfo appInfo = null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 76acf57..bc7bd23 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -235,6 +235,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -942,7 +943,8 @@
.addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
nv.location.toMetricsEventEnum()));
mNotificationRecordLogger.log(
- NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED, r);
+ NotificationRecordLogger.NotificationEvent.fromAction(actionIndex,
+ generatedByAssistant, action.isContextual()), r);
EventLogTags.writeNotificationActionClicked(key, actionIndex,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
nv.rank, nv.count);
@@ -5959,13 +5961,15 @@
}
}
- // limit the number of outstanding notificationrecords an app can have
- int count = getNotificationCountLocked(pkg, userId, id, tag);
- if (count >= MAX_PACKAGE_NOTIFICATIONS) {
- mUsageStats.registerOverCountQuota(pkg);
- Slog.e(TAG, "Package has already posted or enqueued " + count
- + " notifications. Not showing more. package=" + pkg);
- return false;
+ // limit the number of non-fgs outstanding notificationrecords an app can have
+ if (!r.getNotification().isForegroundService()) {
+ int count = getNotificationCountLocked(pkg, userId, id, tag);
+ if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+ mUsageStats.registerOverCountQuota(pkg);
+ Slog.e(TAG, "Package has already posted or enqueued " + count
+ + " notifications. Not showing more. package=" + pkg);
+ return false;
+ }
}
}
}
@@ -6490,7 +6494,7 @@
// Log event to statsd
mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position,
- buzzBeepBlinkLoggingCode);
+ buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey()));
} finally {
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
@@ -6506,6 +6510,21 @@
}
/**
+ *
+ */
+ @GuardedBy("mNotificationLock")
+ InstanceId getGroupInstanceId(String groupKey) {
+ if (groupKey == null) {
+ return null;
+ }
+ NotificationRecord group = mSummaryByGroupKey.get(groupKey);
+ if (group == null) {
+ return null;
+ }
+ return group.getSbn().getInstanceId();
+ }
+
+ /**
* If the notification differs enough visually, consider it a new interruptive notification.
*/
@GuardedBy("mNotificationLock")
@@ -8593,15 +8612,19 @@
com.android.internal.R.string.config_defaultAssistantAccessComponent)
.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
for (int i = 0; i < assistants.size(); i++) {
- String cnString = assistants.valueAt(i);
- if (TextUtils.isEmpty(cnString)) {
+ ComponentName assistantCn = ComponentName
+ .unflattenFromString(assistants.valueAt(i));
+ String packageName = assistants.valueAt(i);
+ if (assistantCn != null) {
+ packageName = assistantCn.getPackageName();
+ }
+ if (TextUtils.isEmpty(packageName)) {
continue;
}
- ArraySet<ComponentName> approved = queryPackageForServices(cnString,
+ ArraySet<ComponentName> approved = queryPackageForServices(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
- for (int k = 0; k < approved.size(); k++) {
- ComponentName cn = approved.valueAt(k);
- addDefaultComponentOrPackage(cn.flattenToString());
+ if (approved.contains(assistantCn)) {
+ addDefaultComponentOrPackage(assistantCn.flattenToString());
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 8e3de15..a9fa2b1 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1382,13 +1382,21 @@
*/
public boolean isConversation() {
Notification notification = getNotification();
- if (mChannel.isDemoted()
- || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
+ if (!Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
+ // very common; don't bother logging
+ return false;
+ }
+ if (mChannel.isDemoted()) {
return false;
}
if (mIsNotConversationOverride) {
return false;
}
+ if (mTargetSdkVersion >= Build.VERSION_CODES.R
+ && Notification.MessagingStyle.class.equals(notification.getNotificationStyle())
+ && mShortcutInfo == null) {
+ return false;
+ }
return true;
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index eba5730..e06e01e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -27,6 +27,7 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -48,10 +49,12 @@
* @param old The previous NotificationRecord. Null if there was no previous record.
* @param position The position at which this notification is ranked.
* @param buzzBeepBlink Logging code reflecting whether this notification alerted the user.
+ * @param groupId The instance Id of the group summary notification, or null.
*/
void maybeLogNotificationPosted(@Nullable NotificationRecord r,
@Nullable NotificationRecord old,
- int position, int buzzBeepBlink);
+ int position, int buzzBeepBlink,
+ InstanceId groupId);
/**
* Logs a notification cancel / dismiss event using UiEventReported (event ids from the
@@ -226,7 +229,7 @@
NOTIFICATION_NOT_POSTED_SNOOZED(319),
@UiEvent(doc = "Notification was clicked.")
NOTIFICATION_CLICKED(320),
- @UiEvent(doc = "Notification action was clicked.")
+ @UiEvent(doc = "Notification action was clicked; unexpected position.")
NOTIFICATION_ACTION_CLICKED(321),
@UiEvent(doc = "Notification detail was expanded due to non-user action.")
NOTIFICATION_DETAIL_OPEN_SYSTEM(327),
@@ -242,7 +245,24 @@
NOTIFICATION_SMART_REPLIED(332),
@UiEvent(doc = "Notification smart reply action was visible.")
NOTIFICATION_SMART_REPLY_VISIBLE(333),
- ;
+ @UiEvent(doc = "App-generated notification action at position 0 was clicked.")
+ NOTIFICATION_ACTION_CLICKED_0(450),
+ @UiEvent(doc = "App-generated notification action at position 1 was clicked.")
+ NOTIFICATION_ACTION_CLICKED_1(451),
+ @UiEvent(doc = "App-generated notification action at position 2 was clicked.")
+ NOTIFICATION_ACTION_CLICKED_2(452),
+ @UiEvent(doc = "Contextual notification action at position 0 was clicked.")
+ NOTIFICATION_CONTEXTUAL_ACTION_CLICKED_0(453),
+ @UiEvent(doc = "Contextual notification action at position 1 was clicked.")
+ NOTIFICATION_CONTEXTUAL_ACTION_CLICKED_1(454),
+ @UiEvent(doc = "Contextual notification action at position 2 was clicked.")
+ NOTIFICATION_CONTEXTUAL_ACTION_CLICKED_2(455),
+ @UiEvent(doc = "Notification assistant generated notification action at 0 was clicked.")
+ NOTIFICATION_ASSIST_ACTION_CLICKED_0(456),
+ @UiEvent(doc = "Notification assistant generated notification action at 1 was clicked.")
+ NOTIFICATION_ASSIST_ACTION_CLICKED_1(457),
+ @UiEvent(doc = "Notification assistant generated notification action at 2 was clicked.")
+ NOTIFICATION_ASSIST_ACTION_CLICKED_2(458);
private final int mId;
NotificationEvent(int id) {
@@ -261,6 +281,21 @@
}
return expanded ? NOTIFICATION_DETAIL_OPEN_SYSTEM : NOTIFICATION_DETAIL_CLOSE_SYSTEM;
}
+ public static NotificationEvent fromAction(int index, boolean isAssistant,
+ boolean isContextual) {
+ if (index < 0 || index > 2) {
+ return NOTIFICATION_ACTION_CLICKED;
+ }
+ if (isAssistant) { // Assistant actions are contextual by definition
+ return NotificationEvent.values()[
+ NOTIFICATION_ASSIST_ACTION_CLICKED_0.ordinal() + index];
+ }
+ if (isContextual) {
+ return NotificationEvent.values()[
+ NOTIFICATION_CONTEXTUAL_ACTION_CLICKED_0.ordinal() + index];
+ }
+ return NotificationEvent.values()[NOTIFICATION_ACTION_CLICKED_0.ordinal() + index];
+ }
}
enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 494ff31..c6ec95a 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.util.FrameworkStatsLog;
@@ -30,7 +31,8 @@
@Override
public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old,
- int position, int buzzBeepBlink) {
+ int position, int buzzBeepBlink,
+ InstanceId groupId) {
NotificationRecordPair p = new NotificationRecordPair(r, old);
if (!p.shouldLogReported(buzzBeepBlink)) {
return;
@@ -43,7 +45,7 @@
/* int32 notification_id_hash = 5 */ p.getNotificationIdHash(),
/* int32 channel_id_hash = 6 */ p.getChannelIdHash(),
/* string group_id_hash = 7 */ p.getGroupIdHash(),
- /* int32 group_instance_id = 8 */ 0, // TODO generate and fill instance ids
+ /* int32 group_instance_id = 8 */ (groupId == null) ? 0 : groupId.getId(),
/* bool is_group_summary = 9 */ r.getSbn().getNotification().isGroupSummary(),
/* string category = 10 */ r.getSbn().getNotification().category,
/* int32 style = 11 */ p.getStyle(),
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index a4b99b3..ec0fc4a 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -166,13 +166,6 @@
private boolean mAllowInvalidShortcuts = false;
- private static final String BADGING_FORCED_TRUE = "force_badging_true_for_bug";
-
- // STOPSHIP (b/142218092) this should be removed before ship
- static boolean wasBadgingForcedTrue(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(), BADGING_FORCED_TRUE, 0) != 0;
- }
-
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
AppOpsManager appOpsManager) {
@@ -183,14 +176,6 @@
mNotificationChannelLogger = notificationChannelLogger;
mAppOps = appOpsManager;
- // STOPSHIP (b/142218092) this should be removed before ship
- if (!wasBadgingForcedTrue(context)) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BADGING,
- DEFAULT_SHOW_BADGE ? 1 : 0);
- Settings.Secure.putInt(context.getContentResolver(), BADGING_FORCED_TRUE, 1);
- }
-
updateBadgingEnabled();
updateBubblesEnabled();
syncChannelsBypassingDnd(mContext.getUserId());
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 4872b66..aafd261 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
@@ -480,7 +481,7 @@
if (allPkgs.length == 0) {
return;
}
- int flags = PackageManager.GET_META_DATA
+ final int flags = PackageManager.GET_META_DATA
| PackageManager.GET_SIGNING_CERTIFICATES
| PackageManager.GET_SIGNATURES;
ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
@@ -489,7 +490,7 @@
for (ApexInfo ai : allPkgs) {
File apexFile = new File(ai.modulePath);
- parallelPackageParser.submit(apexFile, flags);
+ parallelPackageParser.submit(apexFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
parsingApexInfo.put(apexFile, ai);
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 118fdcb..70d1ade 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -725,7 +725,7 @@
}
final PackageSetting callingPkgSetting;
final ArraySet<PackageSetting> callingSharedPkgSettings;
- Trace.beginSection("callingSetting instanceof");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
if (callingSetting instanceof PackageSetting) {
callingPkgSetting = (PackageSetting) callingSetting;
callingSharedPkgSettings = null;
@@ -733,7 +733,7 @@
callingPkgSetting = null;
callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages;
}
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (callingPkgSetting != null) {
if (callingPkgSetting.pkg != null
@@ -769,7 +769,7 @@
return false;
}
final String targetName = targetPkg.getPackageName();
- Trace.beginSection("getAppId");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
final int callingAppId;
if (callingPkgSetting != null) {
callingAppId = callingPkgSetting.appId;
@@ -777,7 +777,7 @@
callingAppId = callingSharedPkgSettings.valueAt(0).appId; // all should be the same
}
final int targetAppId = targetPkgSetting.appId;
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (callingAppId == targetAppId) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "same app id");
@@ -786,7 +786,7 @@
}
try {
- Trace.beginSection("hasPermission");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission");
if (callingSetting.getPermissionsState().hasPermission(
Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) {
if (DEBUG_LOGGING) {
@@ -795,10 +795,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mForceQueryable");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
if (mForceQueryable.contains(targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "force queryable");
@@ -806,10 +806,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mQueriesViaPackage");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage");
if (mQueriesViaPackage.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "queries package");
@@ -817,10 +817,10 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mQueriesViaComponent");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "queries component");
@@ -828,11 +828,11 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mImplicitlyQueryable");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
final int targetUid = UserHandle.getUid(userId, targetAppId);
if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
if (DEBUG_LOGGING) {
@@ -841,11 +841,11 @@
return false;
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
- Trace.beginSection("mOverlayReferenceMapper");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
if (callingSharedPkgSettings != null) {
int size = callingSharedPkgSettings.size();
for (int index = 0; index < size; index++) {
@@ -868,7 +868,7 @@
}
}
} finally {
- Trace.endSection();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 385ace8..c6d08c3 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -16,11 +16,15 @@
package com.android.server.pm;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -864,6 +868,14 @@
}
// Note the target activity doesn't have to be exported.
+ // Flag for bubble
+ ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions);
+ if (options != null && options.isApplyActivityFlagsForBubbles()) {
+ // Flag for bubble to make behaviour match documentLaunchMode=always.
+ intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+
intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intents[0].setSourceBounds(sourceBounds);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3367cd5..5b5f334 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -676,7 +676,7 @@
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
installSource, params, createdMillis,
- stageDir, stageCid, null, false, false, false, null, SessionInfo.INVALID_ID,
+ stageDir, stageCid, null, false, false, false, false, null, SessionInfo.INVALID_ID,
false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
synchronized (mSessions) {
@@ -830,7 +830,7 @@
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
- return session != null
+ return (session != null && !(session.isStaged() && session.isDestroyed()))
? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
: null;
}
@@ -851,7 +851,8 @@
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.userId == userId && !session.hasParentSessionId()) {
+ if (session.userId == userId && !session.hasParentSessionId()
+ && !(session.isStaged() && session.isDestroyed())) {
result.add(session.generateInfoForCaller(false, callingUid));
}
}
@@ -1269,7 +1270,7 @@
public void onStagedSessionChanged(PackageInstallerSession session) {
session.markUpdated();
writeSessionsAsync();
- if (mOkToSendBroadcasts) {
+ if (mOkToSendBroadcasts && !session.isDestroyed()) {
// we don't scrub the data here as this is sent only to the installer several
// privileged system packages
mPm.sendSessionUpdatedBroadcast(
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 9c0ac18..e0d057a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -86,6 +86,8 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
@@ -188,6 +190,7 @@
private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
private static final String ATTR_PREPARED = "prepared";
private static final String ATTR_COMMITTED = "committed";
+ private static final String ATTR_DESTROYED = "destroyed";
private static final String ATTR_SEALED = "sealed";
private static final String ATTR_MULTI_PACKAGE = "multiPackage";
private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
@@ -531,7 +534,7 @@
int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
SessionParams params, long createdMillis,
File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
- boolean committed, boolean sealed,
+ boolean committed, boolean destroyed, boolean sealed,
@Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
String stagedSessionErrorMessage) {
@@ -577,6 +580,7 @@
mPrepared = prepared;
mCommitted = committed;
+ mDestroyed = destroyed;
mStagedSessionReady = isReady;
mStagedSessionFailed = isFailed;
mStagedSessionApplied = isApplied;
@@ -711,6 +715,13 @@
}
}
+ /** {@hide} */
+ boolean isDestroyed() {
+ synchronized (mLock) {
+ return mDestroyed;
+ }
+ }
+
/** Returns true if a staged session has reached a final state and can be forgotten about */
public boolean isStagedAndInTerminalState() {
synchronized (mLock) {
@@ -1066,6 +1077,19 @@
}
/**
+ * Check if the caller is the owner of this session. Otherwise throw a
+ * {@link SecurityException}.
+ */
+ @GuardedBy("mLock")
+ private void assertCallerIsOwnerOrRootOrSystemLocked() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
+ && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Session does not belong to uid " + callingUid);
+ }
+ }
+
+ /**
* If anybody is reading or writing data of the session, throw an {@link SecurityException}.
*/
@GuardedBy("mLock")
@@ -1122,21 +1146,52 @@
}
private void handleStreamValidateAndCommit() {
- boolean success = streamValidateAndCommit();
+ PackageManagerException unrecoverableFailure = null;
+ // This will track whether the session and any children were validated and are ready to
+ // progress to the next phase of install
+ boolean allSessionsReady = false;
+ try {
+ allSessionsReady = streamValidateAndCommit();
+ } catch (PackageManagerException e) {
+ unrecoverableFailure = e;
+ }
if (isMultiPackage()) {
- for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
+ int childCount = mChildSessionIds.size();
+
+ // This will contain all child sessions that do not encounter an unrecoverable failure
+ ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
+
+ for (int i = childCount - 1; i >= 0; --i) {
final int childSessionId = mChildSessionIds.keyAt(i);
// commit all children, regardless if any of them fail; we'll throw/return
// as appropriate once all children have been processed
- if (!mSessionProvider.getSession(childSessionId)
- .streamValidateAndCommit()) {
- success = false;
+ try {
+ PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
+ if (!session.streamValidateAndCommit()) {
+ allSessionsReady = false;
+ }
+ nonFailingSessions.add(session);
+ } catch (PackageManagerException e) {
+ allSessionsReady = false;
+ if (unrecoverableFailure == null) {
+ unrecoverableFailure = e;
+ }
+ }
+ }
+ // If we encountered any unrecoverable failures, destroy all
+ // other impacted sessions besides the parent; that will be cleaned up by the
+ // ChildStatusIntentReceiver.
+ if (unrecoverableFailure != null) {
+ // fail other child sessions that did not already fail
+ for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
+ PackageInstallerSession session = nonFailingSessions.get(i);
+ session.onSessionVerificationFailure(unrecoverableFailure);
}
}
}
- if (!success) {
+ if (!allSessionsReady) {
return;
}
@@ -1216,14 +1271,12 @@
mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
} catch (IntentSender.SendIntentException ignore) {
}
- } else {
+ } else { // failure, let's forward and clean up this session.
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
PackageInstallerSession.this.sessionId);
mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
- } catch (IntentSender.SendIntentException ignore) {
- }
+ onSessionVerificationFailure(status,
+ intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
}
});
}
@@ -1329,7 +1382,13 @@
return true;
}
- private boolean streamValidateAndCommit() {
+ /**
+ * Returns true if the session is successfully validated and committed. Returns false if the
+ * dataloader could not be prepared. This can be called multiple times so long as no
+ * exception is thrown.
+ * @throws PackageManagerException on an unrecoverable error.
+ */
+ private boolean streamValidateAndCommit() throws PackageManagerException {
synchronized (mLock) {
if (mCommitted) {
return true;
@@ -1349,7 +1408,6 @@
mCommitted = true;
}
-
return true;
}
@@ -1449,10 +1507,11 @@
* Prepare DataLoader and stream content for DataLoader sessions.
* Validate the contents of all session.
*
- * @return false if validation failed.
+ * @return false if the data loader could not be prepared.
+ * @throws PackageManagerException when an unrecoverable exception is encountered
*/
@GuardedBy("mLock")
- private boolean streamAndValidateLocked() {
+ private boolean streamAndValidateLocked() throws PackageManagerException {
try {
// Read transfers from the original owner stay open, but as the session's data cannot
// be modified anymore, there is no leak of information. For staged sessions, further
@@ -1472,16 +1531,14 @@
if (params.isStaged) {
mStagingManager.checkNonOverlappingWithStagedSessions(this);
}
-
return true;
} catch (PackageManagerException e) {
- onSessionVerificationFailure(e);
+ throw onSessionVerificationFailure(e);
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- onSessionVerificationFailure(new PackageManagerException(e));
+ throw onSessionVerificationFailure(new PackageManagerException(e));
}
- return false;
}
private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
@@ -1814,13 +1871,44 @@
}
}
- private void logDataLoaderInstallationSession(int returnCode, String extraMessage) {
+ private void logDataLoaderInstallationSession(int returnCode) {
+ // Skip logging the side-loaded app installations, as those are private and aren't reported
+ // anywhere; app stores already have a record of the installation and that's why reporting
+ // it here is fine
+ final String packageNameToLog =
+ (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? mPackageName : "";
final long currentTimestamp = System.currentTimeMillis();
FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
isIncrementalInstallation(),
- mPackageName,
+ packageNameToLog,
currentTimestamp - createdMillis,
- returnCode);
+ returnCode,
+ getApksSize());
+ }
+
+ private long getApksSize() {
+ final PackageSetting ps = mPm.getPackageSetting(mPackageName);
+ if (ps == null) {
+ return 0;
+ }
+ final File apkDirOrPath = ps.codePath;
+ if (apkDirOrPath == null) {
+ return 0;
+ }
+ if (apkDirOrPath.isFile() && apkDirOrPath.getName().toLowerCase().endsWith(".apk")) {
+ return apkDirOrPath.length();
+ }
+ if (!apkDirOrPath.isDirectory()) {
+ return 0;
+ }
+ final File[] files = apkDirOrPath.listFiles();
+ long apksSize = 0;
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].getName().toLowerCase().endsWith(".apk")) {
+ apksSize += files[i].length();
+ }
+ }
+ return apksSize;
}
/**
@@ -1952,15 +2040,16 @@
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (File addedFile : addedFiles) {
- final ApkLite apk;
- try {
- apk = ApkLiteParseUtils.parseApkLite(
- addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (result.isError()) {
+ throw new PackageManagerException(result.getErrorCode(),
+ result.getErrorMessage(), result.getException());
}
+ final ApkLite apk = result.getResult();
if (!stagedSplits.add(apk.splitName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Split " + apk.splitName + " was defined multiple times");
@@ -2049,16 +2138,22 @@
}
} else {
- final PackageLite existing;
- final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
- try {
- existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
- existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
- PackageParser.PARSE_COLLECT_CERTIFICATES);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
+ input.reset(), new File(appInfo.getCodePath()), 0);
+ if (pkgLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
}
+ final PackageLite existing = pkgLiteResult.getResult();
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
+ new File(appInfo.getBaseCodePath()),
+ PackageParser.PARSE_COLLECT_CERTIFICATES);
+ if (apkLiteResult.isError()) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ apkLiteResult.getErrorMessage(), apkLiteResult.getException());
+ }
+ final ApkLite existingBase = apkLiteResult.getResult();
assertApkConsistentLocked("Existing base", existingBase);
@@ -2479,7 +2574,13 @@
+ mParentSessionId + " and may not be abandoned directly.");
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ if (params.isStaged && mDestroyed) {
+ // If a user abandons staged session in an unsafe state, then system will try to
+ // abandon the destroyed staged session when it is safe on behalf of the user.
+ assertCallerIsOwnerOrRootOrSystemLocked();
+ } else {
+ assertCallerIsOwnerOrRootLocked();
+ }
if (isStagedAndInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
@@ -2489,11 +2590,12 @@
return;
}
if (mCommitted && params.isStaged) {
- synchronized (mLock) {
- mDestroyed = true;
+ mDestroyed = true;
+ if (!mStagingManager.abortCommittedSessionLocked(this)) {
+ // Do not clean up the staged session from system. It is not safe yet.
+ mCallback.onStagedSessionChanged(this);
+ return;
}
- mStagingManager.abortCommittedSession(this);
-
cleanStageDir();
}
@@ -2846,13 +2948,14 @@
mCallback.onSessionFinished(this, success);
if (isDataLoaderInstallation()) {
- logDataLoaderInstallationSession(returnCode, msg);
+ logDataLoaderInstallationSession(returnCode);
}
}
/** {@hide} */
void setStagedSessionReady() {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = true;
mStagedSessionApplied = false;
mStagedSessionFailed = false;
@@ -2866,6 +2969,7 @@
void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
String errorMessage) {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = false;
mStagedSessionApplied = false;
mStagedSessionFailed = true;
@@ -2880,6 +2984,7 @@
/** {@hide} */
void setStagedSessionApplied() {
synchronized (mLock) {
+ if (mDestroyed) return; // Do not allow destroyed staged session to change state
mStagedSessionReady = false;
mStagedSessionApplied = true;
mStagedSessionFailed = false;
@@ -3124,7 +3229,7 @@
*/
void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
synchronized (mLock) {
- if (mDestroyed) {
+ if (mDestroyed && !params.isStaged) {
return;
}
@@ -3150,6 +3255,7 @@
}
writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
+ writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed());
writeBooleanAttribute(out, ATTR_SEALED, isSealed());
writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
@@ -3279,6 +3385,7 @@
final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
+ final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED);
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
SessionInfo.INVALID_ID);
@@ -3400,7 +3507,7 @@
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerUid,
installSource, params, createdMillis, stageDir, stageCid, fileArray,
- prepared, committed, sealed, childSessionIdsArray, parentSessionId,
+ prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a4d74f0..bde9d57 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -223,6 +223,7 @@
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -232,6 +233,8 @@
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -2072,8 +2075,18 @@
int autoRevokePermissionsMode,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
- final boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
+ boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
+ final String packageName = res.name;
+ final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
+ if (succeeded && pkgSetting == null) {
+ Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ + "could be executed");
+ res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED;
+ res.returnMsg = "Package was removed before install could complete.";
+ notifyInstallObserver(res, installObserver);
+ return;
+ }
if (succeeded) {
// Send the removed broadcasts
@@ -2117,8 +2130,6 @@
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
- final String packageName = res.pkg.getPackageName();
-
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
int[] firstUserIds = EMPTY_INT_ARRAY;
@@ -2126,7 +2137,7 @@
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
- final PackageSetting ps = getPackageSetting(res.pkg.getPackageName());
+ final PackageSetting ps = pkgSetting;
for (int newUser : res.newUsers) {
final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
@@ -2169,7 +2180,8 @@
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.isSystem();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
+ virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
+ dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
@@ -2263,7 +2275,7 @@
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
FrameworkStatsLog.write(
FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
- packageExternalStorageType, res.pkg.getPackageName());
+ packageExternalStorageType, packageName);
}
}
if (DEBUG_INSTALL) {
@@ -2295,12 +2307,9 @@
if (packageIsBrowser(packageName, userId)) {
// If this browser is restored from user's backup, do not clear
// default-browser state for this user
- synchronized (mLock) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting.getInstallReason(userId)
- != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
- mPermissionManager.setDefaultBrowser(null, true, true, userId);
- }
+ if (pkgSetting.getInstallReason(userId)
+ != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
+ mPermissionManager.setDefaultBrowser(null, true, true, userId);
}
}
@@ -4420,11 +4429,6 @@
if (getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant applications don't have access to this method");
}
- if (!mUserManager.exists(userId)) {
- throw new SecurityException("User doesn't exist");
- }
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "checkPackageStartable");
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -5797,15 +5801,9 @@
@Override
public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
+ if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- if (!mUserManager.exists(userId)) {
- return null;
- }
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "getChangedPackages");
synchronized (mLock) {
if (sequenceNumber >= mChangedPackagesSequenceNumber) {
return null;
@@ -5968,25 +5966,7 @@
|| shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- SigningDetails p1SigningDetails = p1.getSigningDetails();
- SigningDetails p2SigningDetails = p2.getSigningDetails();
- int result = compareSignatures(p1SigningDetails.signatures,
- p2SigningDetails.signatures);
- // To support backwards compatibility with clients of this API expecting pre-key
- // rotation results if either of the packages has a signing lineage the oldest signer
- // in the lineage is used for signature verification.
- if (result != PackageManager.SIGNATURE_MATCH && (
- p1SigningDetails.hasPastSigningCertificates()
- || p2SigningDetails.hasPastSigningCertificates())) {
- Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates()
- ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]}
- : p1SigningDetails.signatures;
- Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
- ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]}
- : p2SigningDetails.signatures;
- result = compareSignatures(p1Signatures, p2Signatures);
- }
- return result;
+ return checkSignaturesInternal(p1.getSigningDetails(), p2.getSigningDetails());
}
}
@@ -6000,21 +5980,21 @@
final int appId2 = UserHandle.getAppId(uid2);
// reader
synchronized (mLock) {
- Signature[] s1;
- Signature[] s2;
+ SigningDetails p1SigningDetails;
+ SigningDetails p2SigningDetails;
Object obj = mSettings.getSettingLPr(appId1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
+ p1SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ps.signatures.mSigningDetails.signatures;
+ p1SigningDetails = ps.signatures.mSigningDetails;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
@@ -6027,23 +6007,53 @@
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
+ p2SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ps.signatures.mSigningDetails.signatures;
+ p2SigningDetails = ps.signatures.mSigningDetails;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return compareSignatures(s1, s2);
+ return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
}
}
+ private int checkSignaturesInternal(SigningDetails p1SigningDetails,
+ SigningDetails p2SigningDetails) {
+ if (p1SigningDetails == null) {
+ return p2SigningDetails == null
+ ? PackageManager.SIGNATURE_NEITHER_SIGNED
+ : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
+ }
+ if (p2SigningDetails == null) {
+ return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
+ }
+ int result = compareSignatures(p1SigningDetails.signatures, p2SigningDetails.signatures);
+ if (result == PackageManager.SIGNATURE_MATCH) {
+ return result;
+ }
+ // To support backwards compatibility with clients of this API expecting pre-key
+ // rotation results if either of the packages has a signing lineage the oldest signer
+ // in the lineage is used for signature verification.
+ if (p1SigningDetails.hasPastSigningCertificates()
+ || p2SigningDetails.hasPastSigningCertificates()) {
+ Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates()
+ ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]}
+ : p1SigningDetails.signatures;
+ Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
+ ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]}
+ : p2SigningDetails.signatures;
+ result = compareSignatures(p1Signatures, p2Signatures);
+ }
+ return result;
+ }
+
@Override
public boolean hasSigningCertificate(
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
@@ -8810,10 +8820,8 @@
private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, false, false, "resolveContentProvider");
flags = updateFlagsForComponent(flags, userId);
+ final int callingUid = Binder.getCallingUid();
final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
if (providerInfo == null) {
return null;
@@ -9064,7 +9072,7 @@
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -12720,13 +12728,14 @@
}
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
- int userId) {
+ int userId, int dataLoaderType) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
final boolean isInstantApp = pkgSetting.getInstantApp(userId);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
- false /*startReceiver*/, pkgSetting.appId, userIds, instantUserIds);
+ false /*startReceiver*/, pkgSetting.appId, userIds, instantUserIds,
+ dataLoaderType);
// Send a session commit broadcast
final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
@@ -12737,7 +12746,8 @@
@Override
public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds) {
+ boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds,
+ int dataLoaderType) {
if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
return;
}
@@ -12746,6 +12756,7 @@
final int uid = UserHandle.getUid(
(ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId);
extras.putInt(Intent.EXTRA_UID, uid);
+ extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, userIds, instantUserIds,
@@ -12863,7 +12874,7 @@
}
}
if (sendAdded) {
- sendPackageAddedForUser(packageName, pkgSetting, userId);
+ sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
return true;
}
if (sendRemoved) {
@@ -13096,7 +13107,7 @@
prepareAppDataAfterInstallLIF(pkgSetting.pkg);
}
}
- sendPackageAddedForUser(packageName, pkgSetting, userId);
+ sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
synchronized (mLock) {
updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
@@ -15245,12 +15256,21 @@
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
- try {
- PackageLite packageInfo =
- new PackageParser().parsePackageLite(origin.file, 0);
- packageName = packageInfo.packageName;
- } catch (PackageParserException e) {
- Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ new ParseTypeImpl(
+ (changeId, packageName1, targetSdkVersion) -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName1;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ return mPackageParserCallback.isChangeEnabled(changeId,
+ appInfo);
+ }).reset(),
+ origin.file, 0);
+ if (result.isError()) {
+ Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
+ result.getException());
+ } else {
+ packageName = result.getResult().packageName;
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
@@ -17059,7 +17079,7 @@
parsedPackage.setSigningDetails(args.signingDetails);
} else {
parsedPackage.setSigningDetails(
- ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
+ ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -18401,7 +18421,8 @@
PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
packageSender.sendPackageAddedForNewUsers(installedInfo.name,
true /*sendBootCompleted*/, false /*startReceiver*/,
- UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers, null);
+ UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers, null,
+ DataLoaderType.NONE);
}
}
@@ -25385,7 +25406,8 @@
final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds,
@Nullable SparseArray<int[]> broadcastWhitelist);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
+ int dataLoaderType);
void notifyPackageAdded(String packageName, int uid);
void notifyPackageChanged(String packageName, int uid);
void notifyPackageRemoved(String packageName, int uid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 88f442c..bc94528 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -51,7 +51,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -63,6 +62,8 @@
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
@@ -505,6 +506,7 @@
long sessionSize = 0;
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (String inPath : inPaths) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
if (fd == null) {
@@ -512,12 +514,19 @@
throw new IllegalArgumentException("Error: Can't open file: " + inPath);
}
try {
- ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
- PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
- null, null);
+ ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), fd.getFileDescriptor(), inPath, 0);
+ if (apkLiteResult.isError()) {
+ throw new IllegalArgumentException(
+ "Error: Failed to parse APK file: " + inPath + ": "
+ + apkLiteResult.getErrorMessage(),
+ apkLiteResult.getException());
+ }
+ PackageLite pkgLite = new PackageLite(null, apkLiteResult.getResult(), null, null,
+ null, null, null, null);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride, fd.getFileDescriptor());
- } catch (PackageParserException | IOException e) {
+ } catch (IOException e) {
getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
throw new IllegalArgumentException(
"Error: Failed to parse APK file: " + inPath, e);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7158af6..9de34a9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3229,60 +3229,66 @@
}
}
- // Read preferred apps from .../etc/preferred-apps directory.
- File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
- if (!preferredDir.exists() || !preferredDir.isDirectory()) {
- return;
- }
- if (!preferredDir.canRead()) {
- Slog.w(TAG, "Directory " + preferredDir + " cannot be read");
- return;
- }
+ // Read preferred apps from .../etc/preferred-apps directories.
+ int size = PackageManagerService.SYSTEM_PARTITIONS.size();
+ for (int index = 0; index < size; index++) {
+ PackageManagerService.ScanPartition partition =
+ PackageManagerService.SYSTEM_PARTITIONS.get(index);
- // Iterate over the files in the directory and scan .xml files
- for (File f : preferredDir.listFiles()) {
- if (!f.getPath().endsWith(".xml")) {
- Slog.i(TAG, "Non-xml file " + f + " in " + preferredDir + " directory, ignoring");
- continue;
- }
- if (!f.canRead()) {
- Slog.w(TAG, "Preferred apps file " + f + " cannot be read");
+ File preferredDir = new File(partition.folder, "etc/preferred-apps");
+ if (!preferredDir.exists() || !preferredDir.isDirectory()) {
continue;
}
- if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
- InputStream str = null;
- try {
- str = new BufferedInputStream(new FileInputStream(f));
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
+ if (!preferredDir.canRead()) {
+ Slog.w(TAG, "Directory " + preferredDir + " cannot be read");
+ continue;
+ }
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
+ // Iterate over the files in the directory and scan .xml files
+ File[] files = preferredDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ continue;
+ }
- if (type != XmlPullParser.START_TAG) {
- Slog.w(TAG, "Preferred apps file " + f + " does not have start tag");
+ for (File f : files) {
+ if (!f.getPath().endsWith(".xml")) {
+ Slog.i(TAG, "Non-xml file " + f + " in " + preferredDir
+ + " directory, ignoring");
continue;
}
- if (!"preferred-activities".equals(parser.getName())) {
- Slog.w(TAG, "Preferred apps file " + f
- + " does not start with 'preferred-activities'");
+ if (!f.canRead()) {
+ Slog.w(TAG, "Preferred apps file " + f + " cannot be read");
continue;
}
- readDefaultPreferredActivitiesLPw(parser, userId);
- } catch (XmlPullParserException e) {
- Slog.w(TAG, "Error reading apps file " + f, e);
- } catch (IOException e) {
- Slog.w(TAG, "Error reading apps file " + f, e);
- } finally {
- if (str != null) {
- try {
- str.close();
- } catch (IOException e) {
+ if (PackageManagerService.DEBUG_PREFERRED) {
+ Log.d(TAG, "Reading default preferred " + f);
+ }
+
+ try (InputStream str = new BufferedInputStream(new FileInputStream(f))) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
}
+
+ if (type != XmlPullParser.START_TAG) {
+ Slog.w(TAG, "Preferred apps file " + f + " does not have start tag");
+ continue;
+ }
+ if (!"preferred-activities".equals(parser.getName())) {
+ Slog.w(TAG, "Preferred apps file " + f
+ + " does not start with 'preferred-activities'");
+ continue;
+ }
+ readDefaultPreferredActivitiesLPw(parser, userId);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Error reading apps file " + f, e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Error reading apps file " + f, e);
}
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9a297d6..a83fa32 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -61,6 +61,7 @@
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
@@ -137,6 +138,9 @@
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
+ if (stagedSession.isDestroyed()) {
+ continue;
+ }
result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
}
}
@@ -202,7 +206,7 @@
final IntArray childSessionIds = new IntArray();
if (session.isMultiPackage()) {
for (int id : session.getChildSessionIds()) {
- if (isApexSession(mStagedSessions.get(id))) {
+ if (isApexSession(getStagedSession(id))) {
childSessionIds.add(id);
}
}
@@ -797,6 +801,8 @@
+ session.sessionId + " [" + errorMessage + "]");
session.setStagedSessionFailed(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
+ mPreRebootVerificationHandler.onPreRebootVerificationComplete(
+ session.sessionId);
return;
}
mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
@@ -880,7 +886,8 @@
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
- if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()) {
+ if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()
+ || stagedSession.isDestroyed()) {
continue;
}
if (stagedSession.isMultiPackage()) {
@@ -943,27 +950,68 @@
}
}
- void abortCommittedSession(@NonNull PackageInstallerSession session) {
+ /**
+ * <p>Abort committed staged session
+ *
+ * <p>This method must be called while holding {@link PackageInstallerSession.mLock}.
+ *
+ * <p>The method returns {@code false} to indicate it is not safe to clean up the session from
+ * system yet. When it is safe, the method returns {@code true}.
+ *
+ * <p> When it is safe to clean up, {@link StagingManager} will call
+ * {@link PackageInstallerSession#abandon()} on the session again.
+ *
+ * @return {@code true} if it is safe to cleanup the session resources, otherwise {@code false}.
+ */
+ boolean abortCommittedSessionLocked(@NonNull PackageInstallerSession session) {
+ int sessionId = session.sessionId;
if (session.isStagedSessionApplied()) {
- Slog.w(TAG, "Cannot abort applied session : " + session.sessionId);
- return;
+ Slog.w(TAG, "Cannot abort applied session : " + sessionId);
+ return false;
}
- abortSession(session);
+ if (!session.isDestroyed()) {
+ throw new IllegalStateException("Committed session must be destroyed before aborting it"
+ + " from StagingManager");
+ }
+ if (getStagedSession(sessionId) == null) {
+ Slog.w(TAG, "Session " + sessionId + " has been abandoned already");
+ return false;
+ }
- boolean hasApex = sessionContainsApex(session);
- if (hasApex) {
- ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
- if (apexSession == null || isApexSessionFinalized(apexSession)) {
- Slog.w(TAG,
- "Cannot abort session " + session.sessionId
- + " because it is not active or APEXD is not reachable");
- return;
- }
- try {
- mApexManager.abortStagedSession(session.sessionId);
- } catch (Exception ignore) {
+ // If pre-reboot verification is running, then return false. StagingManager will call
+ // abandon again when pre-reboot verification ends.
+ if (mPreRebootVerificationHandler.isVerificationRunning(sessionId)) {
+ Slog.w(TAG, "Session " + sessionId + " aborted before pre-reboot "
+ + "verification completed.");
+ return false;
+ }
+
+ // A session could be marked ready once its pre-reboot verification ends
+ if (session.isStagedSessionReady()) {
+ if (sessionContainsApex(session)) {
+ try {
+ ApexSessionInfo apexSession =
+ mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSession == null || isApexSessionFinalized(apexSession)) {
+ Slog.w(TAG,
+ "Cannot abort session " + session.sessionId
+ + " because it is not active.");
+ } else {
+ mApexManager.abortStagedSession(session.sessionId);
+ }
+ } catch (Exception e) {
+ // Failed to contact apexd service. The apex might still be staged. We can still
+ // safely cleanup the staged session since pre-reboot verification is complete.
+ // Also, cleaning up the stageDir prevents the apex from being activated.
+ Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
+ }
}
}
+
+ // Session was successfully aborted from apexd (if required) and pre-reboot verification
+ // is also complete. It is now safe to clean up the session from system.
+ abortSession(session);
+ return true;
}
private boolean isApexSessionFinalized(ApexSessionInfo session) {
@@ -1042,6 +1090,11 @@
// Final states, nothing to do.
return;
}
+ if (session.isDestroyed()) {
+ // Device rebooted before abandoned session was cleaned up.
+ session.abandon();
+ return;
+ }
if (!session.isStagedSessionReady()) {
// The framework got restarted before the pre-reboot verification could complete,
// restart the verification.
@@ -1124,10 +1177,20 @@
}
}
+ private PackageInstallerSession getStagedSession(int sessionId) {
+ PackageInstallerSession session;
+ synchronized (mStagedSessions) {
+ session = mStagedSessions.get(sessionId);
+ }
+ return session;
+ }
+
private final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
private boolean mIsReady;
+ @GuardedBy("mVerificationRunning")
+ private final SparseBooleanArray mVerificationRunning = new SparseBooleanArray();
PreRebootVerificationHandler(Looper looper) {
super(looper);
@@ -1155,13 +1218,15 @@
@Override
public void handleMessage(Message msg) {
final int sessionId = msg.arg1;
- final PackageInstallerSession session;
- synchronized (mStagedSessions) {
- session = mStagedSessions.get(sessionId);
- }
- // Maybe session was aborted before pre-reboot verification was complete
+ final PackageInstallerSession session = getStagedSession(sessionId);
if (session == null) {
- Slog.d(TAG, "Stopping pre-reboot verification for sessionId: " + sessionId);
+ Slog.wtf(TAG, "Session disappeared in the middle of pre-reboot verification: "
+ + sessionId);
+ return;
+ }
+ if (session.isDestroyed()) {
+ // No point in running verification on a destroyed session
+ onPreRebootVerificationComplete(sessionId);
return;
}
switch (msg.what) {
@@ -1200,9 +1265,40 @@
mPendingSessionIds.add(sessionId);
return;
}
+
+ PackageInstallerSession session = getStagedSession(sessionId);
+ synchronized (mVerificationRunning) {
+ // Do not start verification on a session that has been abandoned
+ if (session == null || session.isDestroyed()) {
+ return;
+ }
+ Slog.d(TAG, "Starting preRebootVerification for session " + sessionId);
+ mVerificationRunning.put(sessionId, true);
+ }
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
+ // Things to do when pre-reboot verification completes for a particular sessionId
+ private void onPreRebootVerificationComplete(int sessionId) {
+ // Remove it from mVerificationRunning so that verification is considered complete
+ synchronized (mVerificationRunning) {
+ Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId);
+ mVerificationRunning.delete(sessionId);
+ }
+ // Check if the session was destroyed while pre-reboot verification was running. If so,
+ // abandon it again.
+ PackageInstallerSession session = getStagedSession(sessionId);
+ if (session != null && session.isDestroyed()) {
+ session.abandon();
+ }
+ }
+
+ private boolean isVerificationRunning(int sessionId) {
+ synchronized (mVerificationRunning) {
+ return mVerificationRunning.get(sessionId);
+ }
+ }
+
private void notifyPreRebootVerification_Start_Complete(int sessionId) {
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APEX, sessionId, 0).sendToTarget();
}
@@ -1221,8 +1317,6 @@
* See {@link PreRebootVerificationHandler} to see all nodes of pre reboot verification
*/
private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
- Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
-
if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// If rollback is enabled for this session, we call through to the RollbackManager
// with the list of sessions it must enable rollback for. Note that
@@ -1269,6 +1363,7 @@
}
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
+ onPreRebootVerificationComplete(session.sessionId);
return;
}
@@ -1301,6 +1396,7 @@
// TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
+ onPreRebootVerificationComplete(session.sessionId);
}
}
@@ -1323,9 +1419,18 @@
Slog.e(TAG, "Failed to get hold of StorageManager", e);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
"Failed to get hold of StorageManager");
+ onPreRebootVerificationComplete(session.sessionId);
return;
}
+ // Stop pre-reboot verification before marking session ready. From this point on, if we
+ // abandon the session then it will be cleaned up immediately. If session is abandoned
+ // after this point, then even if for some reason system tries to install the session
+ // or activate its apex, there won't be any files to work with as they will be cleaned
+ // up by the system as part of abandonment. If session is abandoned before this point,
+ // then the session is already destroyed and cannot be marked ready anymore.
+ onPreRebootVerificationComplete(session.sessionId);
+
// Proactively mark session as ready before calling apexd. Although this call order
// looks counter-intuitive, this is the easiest way to ensure that session won't end up
// in the inconsistent state:
@@ -1337,15 +1442,16 @@
// only apex part of the train will be applied, leaving device in an inconsistent state.
Slog.d(TAG, "Marking session " + session.sessionId + " as ready");
session.setStagedSessionReady();
- final boolean hasApex = sessionContainsApex(session);
- if (!hasApex) {
- // Session doesn't contain apex, nothing to do.
- return;
- }
- try {
- mApexManager.markStagedSessionReady(session.sessionId);
- } catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
+ if (session.isStagedSessionReady()) {
+ final boolean hasApex = sessionContainsApex(session);
+ if (hasApex) {
+ try {
+ mApexManager.markStagedSessionReady(session.sessionId);
+ } catch (PackageManagerException e) {
+ session.setStagedSessionFailed(e.error, e.getMessage());
+ return;
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index eb79b6e..d3cd1a9 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -37,6 +37,9 @@
},
{
"include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+ },
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerTest"
}
]
},
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e6af86e..16d96d9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4516,8 +4516,8 @@
switch(cmd) {
case "list":
return runList(pw, shell);
- case "list-missing-system-packages":
- return runListMissingSystemPackages(pw, shell);
+ case "report-system-user-package-whitelist-problems":
+ return runReportPackageWhitelistProblems(pw, shell);
default:
return shell.handleDefaultCommands(cmd);
}
@@ -4584,17 +4584,22 @@
}
}
- private int runListMissingSystemPackages(PrintWriter pw, Shell shell) {
+ private int runReportPackageWhitelistProblems(PrintWriter pw, Shell shell) {
boolean verbose = false;
- boolean force = false;
+ boolean criticalOnly = false;
+ int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE;
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
case "-v":
+ case "--verbose":
verbose = true;
break;
- case "--force":
- force = true;
+ case "--critical-only":
+ criticalOnly = true;
+ break;
+ case "--mode":
+ mode = Integer.parseInt(shell.getNextArgRequired());
break;
default:
pw.println("Invalid option: " + opt);
@@ -4602,8 +4607,12 @@
}
}
+ Slog.d(LOG_TAG, "runReportPackageWhitelistProblems(): verbose=" + verbose
+ + ", criticalOnly=" + criticalOnly
+ + ", mode=" + UserSystemPackageInstaller.modeToString(mode));
+
try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- mSystemPackageInstaller.dumpMissingSystemPackages(ipw, force, verbose);
+ mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly);
}
return 0;
}
@@ -5176,13 +5185,18 @@
final PrintWriter pw = getOutPrintWriter();
pw.println("User manager (user) commands:");
pw.println(" help");
- pw.println(" Print this help text.");
+ pw.println(" Prints this help text.");
pw.println("");
pw.println(" list [-v] [-all]");
pw.println(" Prints all users on the system.");
- pw.println(" list-missing-system-packages [-v] [--force]");
- pw.println(" Prints all system packages that were not explicitly configured to be "
- + "installed.");
+ pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
+ + "[--critical-only] [--mode MODE]");
+ pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
+ pw.println(" -v | --verbose : shows extra info, like number of issues");
+ pw.println(" --critical-only: show only critical issues, excluding warnings");
+ pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
+ + " MODE is the whitelist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)");
}
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 0b6024a..1fec8aa 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -208,7 +208,6 @@
Sets.newArraySet(
UserManager.DISALLOW_CONFIG_DATE_TIME,
UserManager.DISALLOW_CAMERA,
- UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_BLUETOOTH,
UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index cd1087f5..9ec03e5 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -27,7 +27,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Pair;
+import android.util.DebugUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,6 +41,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -111,14 +112,20 @@
* frameworks/base/core/res/res/values/config.xml
*/
static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
+
+ // NOTE: flags below are public so they can used by DebugUtils.flagsToString. And this class
+ // itself is package-protected, so it doesn't matter...
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
+ public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
+ // Used by Shell command only
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_NONE = -1000;
+
@IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
@@ -266,58 +273,56 @@
if (!isLogMode(mode) && !isEnforceMode(mode)) {
return;
}
- final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
- final int size = warnings.size();
- if (size == 0) {
- Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): no warnings");
- return;
- }
+ Slog.v(TAG, "Checking that all system packages are whitelisted.");
- if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
- // Only shows whether all whitelisted packages are indeed on the system.
- for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final boolean isSevere = pair.first;
- if (!isSevere) {
- final String msg = pair.second;
- Slog.w(TAG, msg);
- }
+ // Check whether all whitelisted packages are indeed on the system.
+ final List<String> warnings = getPackagesWhitelistWarnings();
+ final int numberWarnings = warnings.size();
+ if (numberWarnings == 0) {
+ Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has no warnings");
+ } else {
+ Slog.w(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has " + numberWarnings + " warnings:");
+ for (int i = 0; i < numberWarnings; i++) {
+ Slog.w(TAG, warnings.get(i));
}
+ }
+
+ // Check whether all system packages are indeed whitelisted.
+ if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
return;
}
- Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): " + size + " warnings");
+ final List<String> errors = getPackagesWhitelistErrors(mode);
+ final int numberErrors = errors.size();
+
+ if (numberErrors == 0) {
+ Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
+ + ") has no errors");
+ return;
+ }
+ Slog.e(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) + ") has "
+ + numberErrors + " errors:");
+
boolean doWtf = !isImplicitWhitelistMode(mode);
- for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final boolean isSevere = pair.first;
- final String msg = pair.second;
- if (isSevere) {
- if (doWtf) {
- Slog.wtf(TAG, msg);
- } else {
- Slog.e(TAG, msg);
- }
+ for (int i = 0; i < numberWarnings; i++) {
+ final String msg = errors.get(i);
+ if (doWtf) {
+ Slog.wtf(TAG, msg);
} else {
- Slog.w(TAG, msg);
+ Slog.e(TAG, msg);
}
}
}
- // TODO: method below was created to refactor the one-time logging logic so it can be used on
- // dump / cmd as well. It could to be further refactored (for example, creating a new
- // structure for the warnings so it doesn't need a Pair).
/**
- * Gets warnings for system user whitelisting.
- *
- * @return list of warnings, where {@code Pair.first} is the severity ({@code true} for WTF,
- * {@code false} for WARN) and {@code Pair.second} the message.
+ * Gets packages that are listed in the whitelist XML but are not present on the system image.
*/
@NonNull
- private List<Pair<Boolean, String>> checkSystemPackagesWhitelistWarnings(
- @PackageWhitelistMode int mode) {
+ private List<String> getPackagesWhitelistWarnings() {
final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
- final List<Pair<Boolean, String>> warnings = new ArrayList<>();
+ final List<String> warnings = new ArrayList<>();
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Check whether all whitelisted packages are indeed on the system.
@@ -326,25 +331,39 @@
for (String pkgName : allWhitelistedPackages) {
final AndroidPackage pkg = pmInt.getPackage(pkgName);
if (pkg == null) {
- warnings.add(new Pair<>(false, String.format(notPresentFmt, pkgName)));
+ warnings.add(String.format(notPresentFmt, pkgName));
} else if (!pkg.isSystem()) {
- warnings.add(new Pair<>(false, String.format(notSystemFmt, pkgName)));
+ warnings.add(String.format(notSystemFmt, pkgName));
}
}
+ return warnings;
+ }
+
+ /**
+ * Gets packages that are not listed in the whitelist XMLs when they should be.
+ */
+ @NonNull
+ private List<String> getPackagesWhitelistErrors(@PackageWhitelistMode int mode) {
+ if ((!isEnforceMode(mode) || isImplicitWhitelistMode(mode)) && !isLogMode(mode)) {
+ return Collections.emptyList();
+ }
+
+ final List<String> errors = new ArrayList<>();
+ final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
+ final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Check whether all system packages are indeed whitelisted.
final String logMessageFmt = "System package %s is not whitelisted using "
+ "'install-in-user-type' in SystemConfig for any user types!";
- final boolean isSevere = isEnforceMode(mode);
pmInt.forEachPackage(pkg -> {
if (!pkg.isSystem()) return;
final String pkgName = pkg.getManifestPackageName();
if (!allWhitelistedPackages.contains(pkgName)) {
- warnings.add(new Pair<>(isSevere, String.format(logMessageFmt, pkgName)));
+ errors.add(String.format(logMessageFmt, pkgName));
}
});
- return warnings;
+ return errors;
}
/** Whether to only install system packages in new users for which they are whitelisted. */
@@ -420,10 +439,28 @@
if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
return runtimeMode;
}
+ return getDeviceDefaultWhitelistMode();
+ }
+
+ /** Gets the PackageWhitelistMode as defined by {@code config_userTypePackageWhitelistMode}. */
+ private @PackageWhitelistMode int getDeviceDefaultWhitelistMode() {
return Resources.getSystem()
.getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode);
}
+ static @NonNull String modeToString(@PackageWhitelistMode int mode) {
+ // Must handle some types separately because they're not bitwise flags
+ switch (mode) {
+ case USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT:
+ return "DEVICE_DEFAULT";
+ case USER_TYPE_PACKAGE_WHITELIST_MODE_NONE:
+ return "NONE";
+ default:
+ return DebugUtils.flagsToString(UserSystemPackageInstaller.class,
+ "USER_TYPE_PACKAGE_WHITELIST_MODE_", mode);
+ }
+ }
+
/**
* Gets the system packages names that should be installed on the given user.
* See {@link #getInstallablePackagesForUserType(String)}.
@@ -703,34 +740,44 @@
pw.decreaseIndent(); pw.decreaseIndent();
pw.increaseIndent();
- dumpMissingSystemPackages(pw, /* force= */ true, /* verbose= */ true);
+ dumpPackageWhitelistProblems(pw, mode, /* verbose= */ true, /* criticalOnly= */ false);
pw.decreaseIndent();
}
- void dumpMissingSystemPackages(IndentingPrintWriter pw, boolean force, boolean verbose) {
- final int mode = getWhitelistMode();
- final boolean show = force || (isEnforceMode(mode) && !isImplicitWhitelistMode(mode));
- if (!show) return;
+ void dumpPackageWhitelistProblems(IndentingPrintWriter pw, @PackageWhitelistMode int mode,
+ boolean verbose, boolean criticalOnly) {
+ // Handle special cases first
+ if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_NONE) {
+ mode = getWhitelistMode();
+ } else if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
+ mode = getDeviceDefaultWhitelistMode();
+ }
+ Slog.v(TAG, "dumpPackageWhitelistProblems(): using mode " + modeToString(mode));
- final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
- final int size = warnings.size();
+ final List<String> errors = getPackagesWhitelistErrors(mode);
+ showIssues(pw, verbose, errors, "errors");
+ if (criticalOnly) return;
+
+ final List<String> warnings = getPackagesWhitelistWarnings();
+ showIssues(pw, verbose, warnings, "warnings");
+ }
+
+ private static void showIssues(IndentingPrintWriter pw, boolean verbose, List<String> issues,
+ String issueType) {
+ final int size = issues.size();
if (size == 0) {
if (verbose) {
- pw.println("All system packages are accounted for");
+ pw.print("No "); pw.println(issueType);
}
return;
}
-
if (verbose) {
- pw.print(size); pw.println(" warnings for system user:");
+ pw.print(size); pw.print(' '); pw.println(issueType);
pw.increaseIndent();
}
for (int i = 0; i < size; i++) {
- final Pair<Boolean, String> pair = warnings.get(i);
- final String lvl = pair.first ? "WTF" : "WARN";
- final String msg = pair.second;
- pw.print(lvl); pw.print(": "); pw.println(msg);
+ pw.println(issues.get(i));
}
if (verbose) {
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index e860c48..1145057 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
@@ -35,7 +36,7 @@
import android.util.DisplayMetrics;
import android.util.Slog;
-import com.android.server.compat.PlatformCompat;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -58,14 +59,21 @@
*
* This must be called inside the system process as it relies on {@link ServiceManager}.
*/
+ @NonNull
public static PackageParser2 forParsingFileWithDefaults() {
- PlatformCompat platformCompat =
- (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
return new PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
null /* displayMetrics */, null /* cacheDir */, new Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return platformCompat.isChangeEnabled(changeId, appInfo);
+ try {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ } catch (Exception e) {
+ // This shouldn't happen, but assume enforcement if it does
+ Slog.wtf(ParsingUtils.TAG, "IPlatformCompat query failed", e);
+ return true;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 4a1a6a7..a6f02e7 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -241,6 +241,10 @@
return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode());
}
+ /**
+ * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY}
+ * flag and the provided package is not a system package. Otherwise returns {@code true}.
+ */
public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) {
if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
return pkg.isSystem();
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index a635f98..9051d85 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -22,7 +22,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
@@ -60,6 +59,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.util.ArrayUtils;
@@ -222,10 +222,75 @@
private final Context mContext;
private final Object mLock = new Object();
private final PackageManagerInternal mServiceInternal;
- private final PermissionManagerService mPermissionManager;
- DefaultPermissionGrantPolicy(Context context, Looper looper,
- @NonNull PermissionManagerService permissionManager) {
+ /** Directly interact with the PackageManger */
+ private final PackageManagerWrapper NO_PM_CACHE = new PackageManagerWrapper() {
+ @Override
+ public int getPermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ return mContext.getPackageManager().getPermissionFlags(permission, pkg.packageName,
+ user);
+ }
+
+ @Override
+ public void updatePermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ int flagMask, int flagValues, @NonNull UserHandle user) {
+ mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+ flagMask, flagValues, user);
+ }
+
+ @Override
+ public void grantPermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ mContext.getPackageManager().grantRuntimePermission(pkg.packageName, permission,
+ user);
+ }
+
+ @Override
+ public void revokePermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ mContext.getPackageManager().revokeRuntimePermission(pkg.packageName, permission,
+ user);
+ }
+
+ @Override
+ public boolean isGranted(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ return mContext.createContextAsUser(user, 0).getPackageManager().checkPermission(
+ permission, pkg.packageName) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public @Nullable PermissionInfo getPermissionInfo(@NonNull String permissionName) {
+ if (permissionName == null) {
+ return null;
+ }
+
+ try {
+ return mContext.getPackageManager().getPermissionInfo(permissionName, 0);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Permission not found: " + permissionName);
+ return null;
+ }
+ }
+
+ @Override
+ public @Nullable PackageInfo getPackageInfo(@NonNull String pkg) {
+ if (pkg == null) {
+ return null;
+ }
+
+ try {
+ return mContext.getPackageManager().getPackageInfo(pkg,
+ DEFAULT_PACKAGE_INFO_QUERY_FLAGS);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Package not found: " + pkg);
+ return null;
+ }
+ }
+ };
+
+ DefaultPermissionGrantPolicy(Context context, Looper looper) {
mContext = context;
mHandler = new Handler(looper) {
@Override
@@ -233,13 +298,12 @@
if (msg.what == MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS) {
synchronized (mLock) {
if (mGrantExceptions == null) {
- mGrantExceptions = readDefaultPermissionExceptionsLocked();
+ mGrantExceptions = readDefaultPermissionExceptionsLocked(NO_PM_CACHE);
}
}
}
}
};
- mPermissionManager = permissionManager;
mServiceInternal = LocalServices.getService(PackageManagerInternal.class);
}
@@ -293,24 +357,30 @@
}
public void grantDefaultPermissions(int userId) {
- grantPermissionsToSysComponentsAndPrivApps(userId);
- grantDefaultSystemHandlerPermissions(userId);
- grantDefaultPermissionExceptions(userId);
+ DelayingPackageManagerCache pm = new DelayingPackageManagerCache();
+
+ grantPermissionsToSysComponentsAndPrivApps(pm, userId);
+ grantDefaultSystemHandlerPermissions(pm, userId);
+ grantDefaultPermissionExceptions(pm, userId);
+
+ // Apply delayed state
+ pm.apply();
}
- private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
+ private void grantRuntimePermissionsForSystemPackage(PackageManagerWrapper pm,
+ int userId, PackageInfo pkg) {
Set<String> permissions = new ArraySet<>();
for (String permission : pkg.requestedPermissions) {
- final BasePermission bp = mPermissionManager.getPermission(permission);
- if (bp == null) {
+ final PermissionInfo perm = pm.getPermissionInfo(permission);
+ if (perm == null) {
continue;
}
- if (bp.isRuntime()) {
+ if (perm.isRuntime()) {
permissions.add(permission);
}
}
if (!permissions.isEmpty()) {
- grantRuntimePermissions(pkg, permissions, true /*systemFixed*/, userId);
+ grantRuntimePermissions(pm, pkg, permissions, true /*systemFixed*/, userId);
}
}
@@ -318,7 +388,8 @@
mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
}
- private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
+ private void grantPermissionsToSysComponentsAndPrivApps(DelayingPackageManagerCache pm,
+ int userId) {
Log.i(TAG, "Granting permissions to platform components for user " + userId);
List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM);
@@ -326,72 +397,76 @@
if (pkg == null) {
continue;
}
- if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
+
+ // Package info is already loaded, cache it
+ pm.addPackageInfo(pkg.packageName, pkg);
+
+ if (!pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
|| !doesPackageSupportRuntimePermissions(pkg)
|| ArrayUtils.isEmpty(pkg.requestedPermissions)) {
continue;
}
- grantRuntimePermissionsForSystemPackage(userId, pkg);
+ grantRuntimePermissionsForSystemPackage(pm, userId, pkg);
}
}
@SafeVarargs
- private final void grantIgnoringSystemPackage(String packageName, int userId,
- Set<String>... permissionGroups) {
- grantPermissionsToPackage(packageName, userId, true /* ignoreSystemPackage */,
+ private final void grantIgnoringSystemPackage(PackageManagerWrapper pm, String packageName,
+ int userId, Set<String>... permissionGroups) {
+ grantPermissionsToPackage(pm, packageName, userId, true /* ignoreSystemPackage */,
true /*whitelistRestrictedPermissions*/, permissionGroups);
}
@SafeVarargs
- private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId,
- Set<String>... permissionGroups) {
- grantPermissionsToSystemPackage(
- packageName, userId, true /* systemFixed */, permissionGroups);
- }
-
- @SafeVarargs
- private final void grantPermissionsToSystemPackage(
+ private final void grantSystemFixedPermissionsToSystemPackage(PackageManagerWrapper pm,
String packageName, int userId, Set<String>... permissionGroups) {
- grantPermissionsToSystemPackage(
- packageName, userId, false /* systemFixed */, permissionGroups);
+ grantPermissionsToSystemPackage(pm, packageName, userId, true /* systemFixed */,
+ permissionGroups);
}
@SafeVarargs
- private final void grantPermissionsToSystemPackage(String packageName, int userId,
- boolean systemFixed, Set<String>... permissionGroups) {
- if (!isSystemPackage(packageName)) {
+ private final void grantPermissionsToSystemPackage(PackageManagerWrapper pm,
+ String packageName, int userId, Set<String>... permissionGroups) {
+ grantPermissionsToSystemPackage(pm, packageName, userId, false /* systemFixed */,
+ permissionGroups);
+ }
+
+ @SafeVarargs
+ private final void grantPermissionsToSystemPackage(PackageManagerWrapper pm, String packageName,
+ int userId, boolean systemFixed, Set<String>... permissionGroups) {
+ if (!pm.isSystemPackage(packageName)) {
return;
}
- grantPermissionsToPackage(getSystemPackageInfo(packageName),
+ grantPermissionsToPackage(pm, pm.getSystemPackageInfo(packageName),
userId, systemFixed, false /* ignoreSystemPackage */,
true /*whitelistRestrictedPermissions*/, permissionGroups);
}
@SafeVarargs
- private final void grantPermissionsToPackage(String packageName, int userId,
- boolean ignoreSystemPackage, boolean whitelistRestrictedPermissions,
+ private final void grantPermissionsToPackage(PackageManagerWrapper pm, String packageName,
+ int userId, boolean ignoreSystemPackage, boolean whitelistRestrictedPermissions,
Set<String>... permissionGroups) {
- grantPermissionsToPackage(getPackageInfo(packageName),
+ grantPermissionsToPackage(pm, pm.getPackageInfo(packageName),
userId, false /* systemFixed */, ignoreSystemPackage,
whitelistRestrictedPermissions, permissionGroups);
}
@SafeVarargs
- private final void grantPermissionsToPackage(PackageInfo packageInfo, int userId,
- boolean systemFixed, boolean ignoreSystemPackage,
+ private final void grantPermissionsToPackage(PackageManagerWrapper pm, PackageInfo packageInfo,
+ int userId, boolean systemFixed, boolean ignoreSystemPackage,
boolean whitelistRestrictedPermissions, Set<String>... permissionGroups) {
if (packageInfo == null) {
return;
}
if (doesPackageSupportRuntimePermissions(packageInfo)) {
for (Set<String> permissionGroup : permissionGroups) {
- grantRuntimePermissions(packageInfo, permissionGroup, systemFixed,
+ grantRuntimePermissions(pm, packageInfo, permissionGroup, systemFixed,
ignoreSystemPackage, whitelistRestrictedPermissions, userId);
}
}
}
- private void grantDefaultSystemHandlerPermissions(int userId) {
+ private void grantDefaultSystemHandlerPermissions(PackageManagerWrapper pm, int userId) {
Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
final PackagesProvider locationPackagesProvider;
@@ -434,7 +509,7 @@
syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
// Installer
- grantSystemFixedPermissionsToSystemPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
ArrayUtils.firstOrNull(getKnownPackages(
PackageManagerInternal.PACKAGE_INSTALLER, userId)),
userId, STORAGE_PERMISSIONS);
@@ -442,68 +517,68 @@
// Verifier
final String verifier = ArrayUtils.firstOrNull(getKnownPackages(
PackageManagerInternal.PACKAGE_VERIFIER, userId));
- grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS);
- grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, verifier, userId, STORAGE_PERMISSIONS);
+ grantPermissionsToSystemPackage(pm, verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);
// SetupWizard
- grantPermissionsToSystemPackage(
+ grantPermissionsToSystemPackage(pm,
ArrayUtils.firstOrNull(getKnownPackages(
PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId)), userId,
PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
CAMERA_PERMISSIONS);
// Camera
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId),
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, MediaStore.ACTION_IMAGE_CAPTURE, userId),
userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS);
// Sound recorder
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
MediaStore.Audio.Media.RECORD_SOUND_ACTION, userId),
userId, MICROPHONE_PERMISSIONS);
// Media provider
- grantSystemFixedPermissionsToSystemPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId,
STORAGE_PERMISSIONS);
// Downloads provider
- grantSystemFixedPermissionsToSystemPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
getDefaultProviderAuthorityPackage("downloads", userId), userId,
STORAGE_PERMISSIONS);
// Downloads UI
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
DownloadManager.ACTION_VIEW_DOWNLOADS, userId),
userId, STORAGE_PERMISSIONS);
// Storage provider
- grantSystemFixedPermissionsToSystemPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId),
userId, STORAGE_PERMISSIONS);
// CertInstaller
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId,
- STORAGE_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, Credentials.INSTALL_ACTION, userId),
+ userId, STORAGE_PERMISSIONS);
// Dialer
if (dialerAppPackageNames == null) {
String dialerPackage =
- getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId);
- grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ getDefaultSystemHandlerActivityPackage(pm, Intent.ACTION_DIAL, userId);
+ grantDefaultPermissionsToDefaultSystemDialerApp(pm, dialerPackage, userId);
} else {
for (String dialerAppPackageName : dialerAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId);
+ grantDefaultPermissionsToDefaultSystemDialerApp(pm, dialerAppPackageName, userId);
}
}
// Sim call manager
if (simCallManagerPackageNames != null) {
for (String simCallManagerPackageName : simCallManagerPackageNames) {
- grantDefaultPermissionsToDefaultSystemSimCallManager(
+ grantDefaultPermissionsToDefaultSystemSimCallManager(pm,
simCallManagerPackageName, userId);
}
}
@@ -511,77 +586,79 @@
// Use Open Wifi
if (useOpenWifiAppPackageNames != null) {
for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
+ grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(pm,
useOpenWifiPackageName, userId);
}
}
// SMS
if (smsAppPackageNames == null) {
- String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(
+ String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_MESSAGING, userId);
- grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ grantDefaultPermissionsToDefaultSystemSmsApp(pm, smsPackage, userId);
} else {
for (String smsPackage : smsAppPackageNames) {
- grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ grantDefaultPermissionsToDefaultSystemSmsApp(pm, smsPackage, userId);
}
}
// Cell Broadcast Receiver
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, Intents.SMS_CB_RECEIVED_ACTION, userId),
userId, SMS_PERMISSIONS);
// Carrier Provisioning Service
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId),
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerServicePackage(pm, Intents.SMS_CARRIER_PROVISION_ACTION,
+ userId),
userId, SMS_PERMISSIONS);
// Calendar
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_CALENDAR, userId),
userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS);
// Calendar provider
String calendarProvider =
getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId);
- grantPermissionsToSystemPackage(calendarProvider, userId,
+ grantPermissionsToSystemPackage(pm, calendarProvider, userId,
CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, calendarProvider, userId,
+ CALENDAR_PERMISSIONS);
// Calendar provider sync adapters
- grantPermissionToEachSystemPackage(
- getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId),
+ grantPermissionToEachSystemPackage(pm,
+ getHeadlessSyncAdapterPackages(pm, calendarSyncAdapterPackages, userId),
userId, CALENDAR_PERMISSIONS);
// Contacts
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_CONTACTS, userId),
userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
// Contacts provider sync adapters
- grantPermissionToEachSystemPackage(
- getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId),
+ grantPermissionToEachSystemPackage(pm,
+ getHeadlessSyncAdapterPackages(pm, contactsSyncAdapterPackages, userId),
userId, CONTACTS_PERMISSIONS);
// Contacts provider
String contactsProviderPackage =
getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId);
- grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId,
+ grantSystemFixedPermissionsToSystemPackage(pm, contactsProviderPackage, userId,
CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
- grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS);
+ grantPermissionsToSystemPackage(pm, contactsProviderPackage, userId, STORAGE_PERMISSIONS);
// Device provisioning
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
userId, CONTACTS_PERMISSIONS);
// Email
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackageForCategory(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_EMAIL, userId),
userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);
@@ -589,19 +666,19 @@
String browserPackage = ArrayUtils.firstOrNull(getKnownPackages(
PackageManagerInternal.PACKAGE_BROWSER, userId));
if (browserPackage == null) {
- browserPackage = getDefaultSystemHandlerActivityPackageForCategory(
+ browserPackage = getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_APP_BROWSER, userId);
- if (!isSystemPackage(browserPackage)) {
+ if (!pm.isSystemPackage(browserPackage)) {
browserPackage = null;
}
}
- grantPermissionsToPackage(browserPackage, userId, false /* ignoreSystemPackage */,
+ grantPermissionsToPackage(pm, browserPackage, userId, false /* ignoreSystemPackage */,
true /*whitelistRestrictedPermissions*/, FOREGROUND_LOCATION_PERMISSIONS);
// Voice interaction
if (voiceInteractPackageNames != null) {
for (String voiceInteractPackageName : voiceInteractPackageNames) {
- grantPermissionsToSystemPackage(voiceInteractPackageName, userId,
+ grantPermissionsToSystemPackage(pm, voiceInteractPackageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
}
@@ -609,8 +686,8 @@
if (ActivityManager.isLowRamDeviceStatic()) {
// Allow voice search on low-ram devices
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
}
@@ -618,25 +695,26 @@
// Voice recognition
Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE)
.addCategory(Intent.CATEGORY_DEFAULT);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId,
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerServicePackage(pm, voiceRecoIntent, userId), userId,
MICROPHONE_PERMISSIONS);
// Location
if (locationPackageNames != null) {
for (String packageName : locationPackageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
+ grantPermissionsToSystemPackage(pm, packageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+ grantSystemFixedPermissionsToSystemPackage(pm, packageName, userId,
ALWAYS_LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
}
}
if (locationExtraPackageNames != null) {
// Also grant location permission to location extra packages.
for (String packageName : locationExtraPackageNames) {
- grantPermissionsToSystemPackage(packageName, userId, ALWAYS_LOCATION_PERMISSIONS);
+ grantPermissionsToSystemPackage(pm, packageName, userId,
+ ALWAYS_LOCATION_PERMISSIONS);
}
}
@@ -644,72 +722,72 @@
Intent musicIntent = new Intent(Intent.ACTION_VIEW)
.addCategory(Intent.CATEGORY_DEFAULT)
.setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId,
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, musicIntent, userId), userId,
STORAGE_PERMISSIONS);
// Home
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.addCategory(Intent.CATEGORY_LAUNCHER_APP);
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId,
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, homeIntent, userId), userId,
ALWAYS_LOCATION_PERMISSIONS);
// Watches
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
// Home application on watches
- String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(
+ String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(pm,
Intent.CATEGORY_HOME_MAIN, userId);
- grantPermissionsToSystemPackage(wearPackage, userId,
+ grantPermissionsToSystemPackage(pm, wearPackage, userId,
CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
- grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, wearPackage, userId, PHONE_PERMISSIONS);
// Fitness tracking on watches
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId,
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
SENSORS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
}
// Print Spooler
- grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId,
- ALWAYS_LOCATION_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, PrintManager.PRINT_SPOOLER_PACKAGE_NAME,
+ userId, ALWAYS_LOCATION_PERMISSIONS);
// EmergencyInfo
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
// NFC Tag viewer
Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
.setType("vnd.android.cursor.item/ndef_msg");
- grantPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId,
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm, nfcTagIntent, userId), userId,
CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
// Storage Manager
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
StorageManager.ACTION_MANAGE_STORAGE, userId),
userId, STORAGE_PERMISSIONS);
// Companion devices
- grantSystemFixedPermissionsToSystemPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId,
ALWAYS_LOCATION_PERMISSIONS);
// Ringtone Picker
- grantSystemFixedPermissionsToSystemPackage(
- getDefaultSystemHandlerActivityPackage(
+ grantSystemFixedPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
RingtoneManager.ACTION_RINGTONE_PICKER, userId),
userId, STORAGE_PERMISSIONS);
// TextClassifier Service
for (String textClassifierPackage :
getKnownPackages(PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, userId)) {
- grantPermissionsToSystemPackage(textClassifierPackage, userId,
+ grantPermissionsToSystemPackage(pm, textClassifierPackage, userId,
COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
}
@@ -717,7 +795,7 @@
String contentCapturePackageName =
mContext.getPackageManager().getContentCaptureServicePackageName();
if (!TextUtils.isEmpty(contentCapturePackageName)) {
- grantPermissionsToSystemPackage(contentCapturePackageName, userId,
+ grantPermissionsToSystemPackage(pm, contentCapturePackageName, userId,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
}
@@ -726,36 +804,37 @@
String attentionServicePackageName =
mContext.getPackageManager().getAttentionServicePackageName();
if (!TextUtils.isEmpty(attentionServicePackageName)) {
- grantPermissionsToSystemPackage(attentionServicePackageName, userId,
+ grantPermissionsToSystemPackage(pm, attentionServicePackageName, userId,
CAMERA_PERMISSIONS);
}
// There is no real "marker" interface to identify the shared storage backup, it is
// hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
- grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
+ grantSystemFixedPermissionsToSystemPackage(pm, "com.android.sharedstoragebackup", userId,
STORAGE_PERMISSIONS);
// System Captions Service
String systemCaptionsServicePackageName =
mContext.getPackageManager().getSystemCaptionsServicePackageName();
if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
- grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
+ grantPermissionsToSystemPackage(pm, systemCaptionsServicePackageName, userId,
MICROPHONE_PERMISSIONS);
}
}
- private String getDefaultSystemHandlerActivityPackageForCategory(String category, int userId) {
- return getDefaultSystemHandlerActivityPackage(
+ private String getDefaultSystemHandlerActivityPackageForCategory(PackageManagerWrapper pm,
+ String category, int userId) {
+ return getDefaultSystemHandlerActivityPackage(pm,
new Intent(Intent.ACTION_MAIN).addCategory(category), userId);
}
@SafeVarargs
- private final void grantPermissionToEachSystemPackage(
+ private final void grantPermissionToEachSystemPackage(PackageManagerWrapper pm,
ArrayList<String> packages, int userId, Set<String>... permissions) {
if (packages == null) return;
final int count = packages.size();
for (int i = 0; i < count; i++) {
- grantPermissionsToSystemPackage(packages.get(i), userId, permissions);
+ grantPermissionsToSystemPackage(pm, packages.get(i), userId, permissions);
}
}
@@ -763,7 +842,7 @@
return mServiceInternal.getKnownPackageNames(knownPkgId, userId);
}
- private void grantDefaultPermissionsToDefaultSystemDialerApp(
+ private void grantDefaultPermissionsToDefaultSystemDialerApp(PackageManagerWrapper pm,
String dialerPackage, int userId) {
if (dialerPackage == null) {
return;
@@ -771,43 +850,51 @@
boolean isPhonePermFixed =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
if (isPhonePermFixed) {
- grantSystemFixedPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, dialerPackage, userId,
+ PHONE_PERMISSIONS);
} else {
- grantPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+ grantPermissionsToSystemPackage(pm, dialerPackage, userId, PHONE_PERMISSIONS);
}
- grantPermissionsToSystemPackage(dialerPackage, userId,
+ grantPermissionsToSystemPackage(pm, dialerPackage, userId,
CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
}
- private void grantDefaultPermissionsToDefaultSystemSmsApp(String smsPackage, int userId) {
- grantPermissionsToSystemPackage(smsPackage, userId,
+ private void grantDefaultPermissionsToDefaultSystemSmsApp(PackageManagerWrapper pm,
+ String smsPackage, int userId) {
+ grantPermissionsToSystemPackage(pm, smsPackage, userId,
PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
STORAGE_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
}
- private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
+ private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(PackageManagerWrapper pm,
String useOpenWifiPackage, int userId) {
- grantPermissionsToSystemPackage(useOpenWifiPackage, userId, ALWAYS_LOCATION_PERMISSIONS);
+ grantPermissionsToSystemPackage(pm, useOpenWifiPackage, userId,
+ ALWAYS_LOCATION_PERMISSIONS);
}
public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
- grantIgnoringSystemPackage(packageName, userId, ALWAYS_LOCATION_PERMISSIONS);
+ grantIgnoringSystemPackage(NO_PM_CACHE, packageName, userId, ALWAYS_LOCATION_PERMISSIONS);
}
public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+ grantDefaultPermissionsToDefaultSimCallManager(NO_PM_CACHE, packageName, userId);
+ }
+
+ private void grantDefaultPermissionsToDefaultSimCallManager(PackageManagerWrapper pm,
+ String packageName, int userId) {
if (packageName == null) {
return;
}
Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
- grantPermissionsToPackage(packageName, userId, false /* ignoreSystemPackage */,
+ grantPermissionsToPackage(pm, packageName, userId, false /* ignoreSystemPackage */,
true /*whitelistRestrictedPermissions*/, PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
}
- private void grantDefaultPermissionsToDefaultSystemSimCallManager(
+ private void grantDefaultPermissionsToDefaultSystemSimCallManager(PackageManagerWrapper pm,
String packageName, int userId) {
- if (isSystemPackage(packageName)) {
- grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
+ if (pm.isSystemPackage(packageName)) {
+ grantDefaultPermissionsToDefaultSimCallManager(pm, packageName, userId);
}
}
@@ -817,7 +904,7 @@
return;
}
for (String packageName : packageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
+ grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, SMS_PERMISSIONS);
}
}
@@ -828,7 +915,7 @@
return;
}
for (String packageName : packageNames) {
- grantPermissionsToSystemPackage(packageName, userId,
+ grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
CAMERA_PERMISSIONS, CONTACTS_PERMISSIONS);
}
@@ -843,7 +930,7 @@
for (String packageName : packageNames) {
// Grant these permissions as system-fixed, so that nobody can accidentally
// break cellular data.
- grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+ grantSystemFixedPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
PHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
}
}
@@ -855,17 +942,20 @@
return;
}
for (String packageName : packageNames) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
- if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
- revokeRuntimePermissions(packageName, PHONE_PERMISSIONS, true, userId);
- revokeRuntimePermissions(packageName, ALWAYS_LOCATION_PERMISSIONS, true, userId);
+ PackageInfo pkg = NO_PM_CACHE.getSystemPackageInfo(packageName);
+ if (NO_PM_CACHE.isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+ revokeRuntimePermissions(NO_PM_CACHE, packageName, PHONE_PERMISSIONS, true,
+ userId);
+ revokeRuntimePermissions(NO_PM_CACHE, packageName, ALWAYS_LOCATION_PERMISSIONS,
+ true, userId);
}
}
}
public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
Log.i(TAG, "Granting permissions to active LUI app for user:" + userId);
- grantSystemFixedPermissionsToSystemPackage(packageName, userId, CAMERA_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
+ CAMERA_PERMISSIONS);
}
public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
@@ -874,23 +964,27 @@
return;
}
for (String packageName : packageNames) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
- if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
- revokeRuntimePermissions(packageName, CAMERA_PERMISSIONS, true, userId);
+ PackageInfo pkg = NO_PM_CACHE.getSystemPackageInfo(packageName);
+ if (NO_PM_CACHE.isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+ revokeRuntimePermissions(NO_PM_CACHE, packageName, CAMERA_PERMISSIONS, true,
+ userId);
}
}
}
public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default browser for user:" + userId);
- grantPermissionsToSystemPackage(packageName, userId, FOREGROUND_LOCATION_PERMISSIONS);
+ grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
+ FOREGROUND_LOCATION_PERMISSIONS);
}
- private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) {
- return getDefaultSystemHandlerActivityPackage(new Intent(intentAction), userId);
+ private String getDefaultSystemHandlerActivityPackage(PackageManagerWrapper pm,
+ String intentAction, int userId) {
+ return getDefaultSystemHandlerActivityPackage(pm, new Intent(intentAction), userId);
}
- private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
+ private String getDefaultSystemHandlerActivityPackage(PackageManagerWrapper pm, Intent intent,
+ int userId) {
ResolveInfo handler = mContext.getPackageManager().resolveActivityAsUser(
intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
if (handler == null || handler.activityInfo == null) {
@@ -900,14 +994,15 @@
return null;
}
String packageName = handler.activityInfo.packageName;
- return isSystemPackage(packageName) ? packageName : null;
+ return pm.isSystemPackage(packageName) ? packageName : null;
}
- private String getDefaultSystemHandlerServicePackage(String intentAction, int userId) {
- return getDefaultSystemHandlerServicePackage(new Intent(intentAction), userId);
+ private String getDefaultSystemHandlerServicePackage(PackageManagerWrapper pm,
+ String intentAction, int userId) {
+ return getDefaultSystemHandlerServicePackage(pm, new Intent(intentAction), userId);
}
- private String getDefaultSystemHandlerServicePackage(
+ private String getDefaultSystemHandlerServicePackage(PackageManagerWrapper pm,
Intent intent, int userId) {
List<ResolveInfo> handlers = mContext.getPackageManager().queryIntentServicesAsUser(
intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
@@ -918,14 +1013,14 @@
for (int i = 0; i < handlerCount; i++) {
ResolveInfo handler = handlers.get(i);
String handlerPackage = handler.serviceInfo.packageName;
- if (isSystemPackage(handlerPackage)) {
+ if (pm.isSystemPackage(handlerPackage)) {
return handlerPackage;
}
}
return null;
}
- private ArrayList<String> getHeadlessSyncAdapterPackages(
+ private ArrayList<String> getHeadlessSyncAdapterPackages(PackageManagerWrapper pm,
String[] syncAdapterPackageNames, int userId) {
ArrayList<String> syncAdapterPackages = new ArrayList<>();
@@ -940,7 +1035,7 @@
continue;
}
- if (isSystemPackage(syncAdapterPackageName)) {
+ if (pm.isSystemPackage(syncAdapterPackageName)) {
syncAdapterPackages.add(syncAdapterPackageName);
}
}
@@ -957,27 +1052,15 @@
return null;
}
- private boolean isSystemPackage(String packageName) {
- return isSystemPackage(getPackageInfo(packageName));
- }
-
- private boolean isSystemPackage(PackageInfo pkg) {
- if (pkg == null) {
- return false;
- }
- return pkg.applicationInfo.isSystemApp()
- && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg);
- }
-
- private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions,
- boolean systemFixed, int userId) {
- grantRuntimePermissions(pkg, permissions, systemFixed, false,
+ private void grantRuntimePermissions(PackageManagerWrapper pm, PackageInfo pkg,
+ Set<String> permissions, boolean systemFixed, int userId) {
+ grantRuntimePermissions(pm, pkg, permissions, systemFixed, false,
true /*whitelistRestrictedPermissions*/, userId);
}
- private void revokeRuntimePermissions(String packageName, Set<String> permissions,
- boolean systemFixed, int userId) {
- PackageInfo pkg = getSystemPackageInfo(packageName);
+ private void revokeRuntimePermissions(PackageManagerWrapper pm, String packageName,
+ Set<String> permissions, boolean systemFixed, int userId) {
+ PackageInfo pkg = pm.getSystemPackageInfo(packageName);
if (pkg == null || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
return;
}
@@ -990,8 +1073,8 @@
}
UserHandle user = UserHandle.of(userId);
- final int flags = mContext.getPackageManager()
- .getPermissionFlags(permission, packageName, user);
+ final int flags = pm.getPermissionFlags(permission, pm.getPackageInfo(packageName),
+ user);
// We didn't get this through the default grant policy. Move along.
if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -1007,7 +1090,7 @@
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
continue;
}
- mContext.getPackageManager().revokeRuntimePermission(packageName, permission, user);
+ pm.revokePermission(permission, pkg, user);
if (DEBUG) {
Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
@@ -1017,7 +1100,7 @@
// Remove the GRANTED_BY_DEFAULT flag without touching the others.
// Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
// sticky once set.
- mContext.getPackageManager().updatePermissionFlags(permission, packageName,
+ pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, user);
}
}
@@ -1040,25 +1123,8 @@
| PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
}
- /**
- * Return the background permission for a permission.
- *
- * @param permission The name of the foreground permission
- *
- * @return The name of the background permission or {@code null} if the permission has no
- * background permission
- */
- private @Nullable String getBackgroundPermission(@NonNull String permission) {
- try {
- return mContext.getPackageManager().getPermissionInfo(permission,
- 0).backgroundPermission;
- } catch (NameNotFoundException e) {
- return null;
- }
- }
-
- private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissionsWithoutSplits,
- boolean systemFixed, boolean ignoreSystemPackage,
+ private void grantRuntimePermissions(PackageManagerWrapper pm, PackageInfo pkg,
+ Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
boolean whitelistRestrictedPermissions, int userId) {
UserHandle user = UserHandle.of(userId);
if (pkg == null) {
@@ -1072,7 +1138,8 @@
// Intersect the requestedPermissions for a factory image with that of its current update
// in case the latter one removed a <uses-permission>
- String[] requestedByNonSystemPackage = getPackageInfo(pkg.packageName).requestedPermissions;
+ String[] requestedByNonSystemPackage = pm.getPackageInfo(pkg.packageName)
+ .requestedPermissions;
int size = requestedPermissions.length;
for (int i = 0; i < size; i++) {
if (!ArrayUtils.contains(requestedByNonSystemPackage, requestedPermissions[i])) {
@@ -1081,14 +1148,6 @@
}
requestedPermissions = ArrayUtils.filterNotNull(requestedPermissions, String[]::new);
- PackageManager pm;
- try {
- pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
- user).getPackageManager();
- } catch (NameNotFoundException doesNotHappen) {
- throw new IllegalStateException(doesNotHappen);
- }
-
final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
ApplicationInfo applicationInfo = pkg.applicationInfo;
@@ -1123,7 +1182,7 @@
if (!ignoreSystemPackage
&& applicationInfo != null
&& applicationInfo.isUpdatedSystemApp()) {
- final PackageInfo disabledPkg = getSystemPackageInfo(
+ final PackageInfo disabledPkg = pm.getSystemPackageInfo(
mServiceInternal.getDisabledSystemPackageName(pkg.packageName));
if (disabledPkg != null) {
if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
@@ -1145,7 +1204,7 @@
int numOther = 0;
for (int i = 0; i < numRequestedPermissions; i++) {
String permission = requestedPermissions[i];
- if (getBackgroundPermission(permission) != null) {
+ if (pm.getBackgroundPermission(permission) != null) {
sortedRequestedPermissions[numForeground] = permission;
numForeground++;
} else {
@@ -1166,8 +1225,7 @@
}
if (permissions.contains(permission)) {
- final int flags = mContext.getPackageManager().getPermissionFlags(
- permission, pkg.packageName, user);
+ final int flags = pm.getPermissionFlags(permission, pkg, user);
// If we are trying to grant as system fixed and already system fixed
// then the system can change the system fixed grant state.
@@ -1194,9 +1252,8 @@
newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
// If we are whitelisting the permission, update the exempt flag before grant.
- if (whitelistRestrictedPermissions && isPermissionRestricted(permission)) {
- mContext.getPackageManager().updatePermissionFlags(permission,
- pkg.packageName,
+ if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)) {
+ pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
}
@@ -1204,82 +1261,15 @@
// If the system tries to change a system fixed permission from one fixed
// state to another we need to drop the fixed flag to allow the grant.
if (changingGrantForSystemFixed) {
- mContext.getPackageManager().updatePermissionFlags(permission,
- pkg.packageName, flags,
+ pm.updatePermissionFlags(permission, pkg, flags,
flags & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, user);
}
- if (pm.checkPermission(permission, pkg.packageName)
- != PackageManager.PERMISSION_GRANTED) {
- mContext.getPackageManager()
- .grantRuntimePermission(pkg.packageName, permission, user);
+ if (!pm.isGranted(permission, pkg, user)) {
+ pm.grantPermission(permission, pkg, user);
}
- mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
- newFlags, newFlags, user);
-
- int uid = UserHandle.getUid(userId,
- UserHandle.getAppId(pkg.applicationInfo.uid));
-
- List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
- .get(permission);
- if (fgPerms != null) {
- int numFgPerms = fgPerms.size();
- for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
- String fgPerm = fgPerms.get(fgPermNum);
-
- if (pm.checkPermission(fgPerm, pkg.packageName)
- == PackageManager.PERMISSION_GRANTED) {
- // Upgrade the app-op state of the fg permission to allow bg access
- // TODO: Dont' call app ops from package manager code.
- mContext.getSystemService(AppOpsManager.class).setUidMode(
- AppOpsManager.permissionToOp(fgPerm), uid,
- AppOpsManager.MODE_ALLOWED);
-
- break;
- }
- }
- }
-
- String bgPerm = getBackgroundPermission(permission);
- String op = AppOpsManager.permissionToOp(permission);
- if (bgPerm == null) {
- if (op != null) {
- // TODO: Dont' call app ops from package manager code.
- mContext.getSystemService(AppOpsManager.class).setUidMode(op, uid,
- AppOpsManager.MODE_ALLOWED);
- }
- } else {
- int mode;
- if (pm.checkPermission(bgPerm, pkg.packageName)
- == PackageManager.PERMISSION_GRANTED) {
- mode = AppOpsManager.MODE_ALLOWED;
- } else {
- mode = AppOpsManager.MODE_FOREGROUND;
- }
-
- mContext.getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
- }
-
- if (DEBUG) {
- Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
- + permission + " to default handler " + pkg);
-
- int appOp = AppOpsManager.permissionToOpCode(permission);
- if (appOp != AppOpsManager.OP_NONE
- && AppOpsManager.opToDefaultMode(appOp)
- != AppOpsManager.MODE_ALLOWED) {
- // Permission has a corresponding appop which is not allowed by default
- // We must allow it as well, as it's usually checked alongside the
- // permission
- if (DEBUG) {
- Log.i(TAG, "Granting OP_" + AppOpsManager.opToName(appOp)
- + " to " + pkg.packageName);
- }
- mContext.getSystemService(AppOpsManager.class).setUidMode(
- appOp, pkg.applicationInfo.uid, AppOpsManager.MODE_ALLOWED);
- }
- }
+ pm.updatePermissionFlags(permission, pkg, newFlags, newFlags, user);
}
// If a component gets a permission for being the default handler A
@@ -1291,57 +1281,14 @@
Log.i(TAG, "Granted not fixed " + permission + " to default handler "
+ pkg);
}
- mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+ pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, user);
}
}
}
}
- private PackageInfo getSystemPackageInfo(String pkg) {
- return getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
- }
-
- private PackageInfo getPackageInfo(String pkg) {
- return getPackageInfo(pkg, 0 /* extraFlags */);
- }
-
- private PackageInfo getPackageInfo(String pkg,
- @PackageManager.PackageInfoFlags int extraFlags) {
- if (pkg == null) {
- return null;
- }
- try {
- return mContext.getPackageManager().getPackageInfo(pkg,
- DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags);
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "PackageNot found: " + pkg, e);
- return null;
- }
- }
-
- private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
- if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
- return true;
- }
- if (!pkg.applicationInfo.isPrivilegedApp()) {
- return false;
- }
- final PackageInfo disabledPkg = getSystemPackageInfo(
- mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
- if (disabledPkg != null) {
- ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
- if (disabledPackageAppInfo != null
- && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
- return false;
- }
- } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
- return false;
- }
- return mServiceInternal.isPlatformSigned(pkg.packageName);
- }
-
- private void grantDefaultPermissionExceptions(int userId) {
+ private void grantDefaultPermissionExceptions(PackageManagerWrapper pm, int userId) {
mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
synchronized (mLock) {
@@ -1350,7 +1297,7 @@
// performed for every user. If there is an entry then the app
// is on the system image and supports runtime permissions.
if (mGrantExceptions == null) {
- mGrantExceptions = readDefaultPermissionExceptionsLocked();
+ mGrantExceptions = readDefaultPermissionExceptionsLocked(pm);
}
}
@@ -1358,12 +1305,12 @@
final int exceptionCount = mGrantExceptions.size();
for (int i = 0; i < exceptionCount; i++) {
String packageName = mGrantExceptions.keyAt(i);
- PackageInfo pkg = getSystemPackageInfo(packageName);
+ PackageInfo pkg = pm.getSystemPackageInfo(packageName);
List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
final int permissionGrantCount = permissionGrants.size();
for (int j = 0; j < permissionGrantCount; j++) {
DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
- if (!isPermissionDangerous(permissionGrant.name)) {
+ if (!pm.isPermissionDangerous(permissionGrant.name)) {
Log.w(TAG, "Ignoring permission " + permissionGrant.name
+ " which isn't dangerous");
continue;
@@ -1376,7 +1323,7 @@
permissions.add(permissionGrant.name);
- grantRuntimePermissions(pkg, permissions, permissionGrant.fixed,
+ grantRuntimePermissions(pm, pkg, permissions, permissionGrant.fixed,
permissionGrant.whitelisted, true /*whitelistRestrictedPermissions*/,
userId);
}
@@ -1416,7 +1363,7 @@
}
private @NonNull ArrayMap<String, List<DefaultPermissionGrant>>
- readDefaultPermissionExceptionsLocked() {
+ readDefaultPermissionExceptionsLocked(PackageManagerWrapper pm) {
File[] files = getDefaultPermissionFiles();
if (files == null) {
return new ArrayMap<>(0);
@@ -1440,7 +1387,7 @@
) {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, null);
- parse(parser, grantExceptions);
+ parse(pm, parser, grantExceptions);
} catch (XmlPullParserException | IOException e) {
Slog.w(TAG, "Error reading default permissions file " + file, e);
}
@@ -1449,8 +1396,9 @@
return grantExceptions;
}
- private void parse(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
- outGrantExceptions) throws IOException, XmlPullParserException {
+ private void parse(PackageManagerWrapper pm, XmlPullParser parser,
+ Map<String, List<DefaultPermissionGrant>> outGrantExceptions)
+ throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1459,15 +1407,16 @@
continue;
}
if (TAG_EXCEPTIONS.equals(parser.getName())) {
- parseExceptions(parser, outGrantExceptions);
+ parseExceptions(pm, parser, outGrantExceptions);
} else {
Log.e(TAG, "Unknown tag " + parser.getName());
}
}
}
- private void parseExceptions(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
- outGrantExceptions) throws IOException, XmlPullParserException {
+ private void parseExceptions(PackageManagerWrapper pm, XmlPullParser parser,
+ Map<String, List<DefaultPermissionGrant>> outGrantExceptions)
+ throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1482,7 +1431,7 @@
outGrantExceptions.get(packageName);
if (packageExceptions == null) {
// The package must be on the system image
- PackageInfo packageInfo = getSystemPackageInfo(packageName);
+ PackageInfo packageInfo = pm.getSystemPackageInfo(packageName);
if (packageInfo == null) {
Log.w(TAG, "No such package:" + packageName);
@@ -1490,7 +1439,7 @@
continue;
}
- if (!isSystemPackage(packageInfo)) {
+ if (!pm.isSystemPackage(packageInfo)) {
Log.w(TAG, "Unknown system package:" + packageName);
XmlUtils.skipCurrentTag(parser);
continue;
@@ -1549,21 +1498,349 @@
&& pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
}
- private boolean isPermissionRestricted(String name) {
- try {
- return mContext.getPackageManager().getPermissionInfo(name, 0).isRestricted();
- } catch (NameNotFoundException e) {
- return false;
+ /**
+ * A wrapper for package manager calls done by this class
+ */
+ private abstract class PackageManagerWrapper {
+ abstract int getPermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user);
+
+ abstract void updatePermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ int flagMask, int flagValues, @NonNull UserHandle user);
+
+ abstract void grantPermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user);
+
+ abstract void revokePermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user);
+
+ abstract boolean isGranted(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user);
+
+ abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permissionName);
+
+ abstract @Nullable PackageInfo getPackageInfo(@NonNull String pkg);
+
+ @Nullable PackageInfo getSystemPackageInfo(@NonNull String pkg) {
+ PackageInfo pi = getPackageInfo(pkg);
+ if (pi == null || !pi.applicationInfo.isSystemApp()) {
+ return null;
+ }
+ return pi;
+ }
+
+ boolean isPermissionRestricted(@NonNull String name) {
+ PermissionInfo pi = getPermissionInfo(name);
+ if (pi == null) {
+ return false;
+ }
+
+ return pi.isRestricted();
+ }
+
+ boolean isPermissionDangerous(@NonNull String name) {
+ PermissionInfo pi = getPermissionInfo(name);
+ if (pi == null) {
+ return false;
+ }
+
+ return pi.getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
+ }
+
+ /**
+ * Return the background permission for a permission.
+ *
+ * @param permission The name of the foreground permission
+ *
+ * @return The name of the background permission or {@code null} if the permission has no
+ * background permission
+ */
+ @Nullable String getBackgroundPermission(@NonNull String permission) {
+ PermissionInfo pi = getPermissionInfo(permission);
+ if (pi == null) {
+ return null;
+ }
+
+ return pi.backgroundPermission;
+ }
+
+ boolean isSystemPackage(@Nullable String packageName) {
+ return isSystemPackage(getPackageInfo(packageName));
+ }
+
+ boolean isSystemPackage(@Nullable PackageInfo pkg) {
+ if (pkg == null) {
+ return false;
+ }
+ return pkg.applicationInfo.isSystemApp()
+ && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg);
+ }
+
+ boolean isSysComponentOrPersistentPlatformSignedPrivApp(@NonNull PackageInfo pkg) {
+ if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ if (!pkg.applicationInfo.isPrivilegedApp()) {
+ return false;
+ }
+ final PackageInfo disabledPkg = getSystemPackageInfo(
+ mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
+ if (disabledPkg != null) {
+ ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
+ if (disabledPackageAppInfo != null
+ && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ return false;
+ }
+ } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ return false;
+ }
+ return mServiceInternal.isPlatformSigned(pkg.packageName);
}
}
- private boolean isPermissionDangerous(String name) {
- try {
- final PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(name, 0);
- return (pi.getProtection() == PermissionInfo.PROTECTION_DANGEROUS);
- } catch (NameNotFoundException e) {
- // When unknown assume it's dangerous to be on the safe side
- return true;
+ /**
+ * Do package manager calls but cache state and delay any change until {@link #apply()} is
+ * called
+ */
+ private class DelayingPackageManagerCache extends PackageManagerWrapper {
+ /** uid -> permission -> isGranted, flags */
+ private SparseArray<ArrayMap<String, PermissionState>> mDelayedPermissionState =
+ new SparseArray<>();
+ /** userId -> context */
+ private SparseArray<Context> mUserContexts = new SparseArray<>();
+ /** Permission name -> info */
+ private ArrayMap<String, PermissionInfo> mPermissionInfos = new ArrayMap<>();
+ /** Package name -> info */
+ private ArrayMap<String, PackageInfo> mPackageInfos = new ArrayMap<>();
+
+ /**
+ * Apply the cached state
+ */
+ void apply() {
+ PackageManager.corkPackageInfoCache();
+ for (int uidIdx = 0; uidIdx < mDelayedPermissionState.size(); uidIdx++) {
+ for (int permIdx = 0; permIdx < mDelayedPermissionState.valueAt(uidIdx).size();
+ permIdx++) {
+ try {
+ mDelayedPermissionState.valueAt(uidIdx).valueAt(permIdx).apply();
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Cannot set permission " + mDelayedPermissionState.valueAt(
+ uidIdx).keyAt(permIdx) + " of uid " + mDelayedPermissionState.keyAt(
+ uidIdx), e);
+ }
+ }
+ }
+ PackageManager.uncorkPackageInfoCache();
+ }
+
+ void addPackageInfo(@NonNull String packageName, @NonNull PackageInfo pkg) {
+ mPackageInfos.put(packageName, pkg);
+ }
+
+ private @NonNull Context createContextAsUser(@NonNull UserHandle user) {
+ int index = mUserContexts.indexOfKey(user.getIdentifier());
+ if (index >= 0) {
+ return mUserContexts.valueAt(index);
+ }
+
+ Context uc = mContext.createContextAsUser(user, 0);
+
+ mUserContexts.put(user.getIdentifier(), uc);
+
+ return uc;
+ }
+
+ private @NonNull PermissionState getPermissionState(@NonNull String permission,
+ @NonNull PackageInfo pkg, @NonNull UserHandle user) {
+ int uid = UserHandle.getUid(user.getIdentifier(),
+ UserHandle.getAppId(pkg.applicationInfo.uid));
+ int uidIdx = mDelayedPermissionState.indexOfKey(uid);
+
+ ArrayMap<String, PermissionState> uidState;
+ if (uidIdx >= 0) {
+ uidState = mDelayedPermissionState.valueAt(uidIdx);
+ } else {
+ uidState = new ArrayMap<>();
+ mDelayedPermissionState.put(uid, uidState);
+ }
+
+ int permIdx = uidState.indexOfKey(permission);
+
+ PermissionState permState;
+ if (permIdx >= 0) {
+ permState = uidState.valueAt(permIdx);
+ } else {
+ permState = new PermissionState(permission, pkg, user);
+ uidState.put(permission, permState);
+ }
+
+ return permState;
+ }
+
+ @Override
+ public int getPermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ PermissionState state = getPermissionState(permission, pkg, user);
+ state.initFlags();
+ return state.newFlags;
+ }
+
+ @Override
+ public void updatePermissionFlags(@NonNull String permission, @NonNull PackageInfo pkg,
+ int flagMask, int flagValues, @NonNull UserHandle user) {
+ PermissionState state = getPermissionState(permission, pkg, user);
+ state.initFlags();
+ state.newFlags |= flagValues & flagMask;
+ }
+
+ @Override
+ public void grantPermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ PermissionState state = getPermissionState(permission, pkg, user);
+ state.initGranted();
+ state.newGranted = true;
+ }
+
+ @Override
+ public void revokePermission(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ PermissionState state = getPermissionState(permission, pkg, user);
+ state.initGranted();
+ state.newGranted = false;
+ }
+
+ @Override
+ public boolean isGranted(@NonNull String permission, @NonNull PackageInfo pkg,
+ @NonNull UserHandle user) {
+ PermissionState state = getPermissionState(permission, pkg, user);
+ state.initGranted();
+ return state.newGranted;
+ }
+
+ @Override
+ public @Nullable PermissionInfo getPermissionInfo(@NonNull String permissionName) {
+ int index = mPermissionInfos.indexOfKey(permissionName);
+ if (index >= 0) {
+ return mPermissionInfos.valueAt(index);
+ }
+
+ PermissionInfo pi = NO_PM_CACHE.getPermissionInfo(permissionName);
+ mPermissionInfos.put(permissionName, pi);
+
+ return pi;
+ }
+
+ @Override
+ public @Nullable PackageInfo getPackageInfo(@NonNull String pkg) {
+ int index = mPackageInfos.indexOfKey(pkg);
+ if (index >= 0) {
+ return mPackageInfos.valueAt(index);
+ }
+
+ PackageInfo pi = NO_PM_CACHE.getPackageInfo(pkg);
+ mPackageInfos.put(pkg, pi);
+
+ return pi;
+ }
+
+ /**
+ * State of a single permission belonging to a single uid
+ */
+ private class PermissionState {
+ private final @NonNull String mPermission;
+ private final @NonNull PackageInfo mPkgRequestingPerm;
+ private final @NonNull UserHandle mUser;
+
+ /** Permission flags when the state was created */
+ private @Nullable Integer mOriginalFlags;
+ /** Altered permission flags or {@code null} if no change was requested */
+ @Nullable Integer newFlags;
+
+ /** Grant state when the state was created */
+ private @Nullable Boolean mOriginalGranted;
+ /** Altered grant state or {@code null} if no change was requested */
+ @Nullable Boolean newGranted;
+
+ private PermissionState(@NonNull String permission,
+ @NonNull PackageInfo pkgRequestingPerm, @NonNull UserHandle user) {
+ mPermission = permission;
+ mPkgRequestingPerm = pkgRequestingPerm;
+ mUser = user;
+ }
+
+ /**
+ * Apply the changes to the permission to the system
+ */
+ void apply() {
+ if (DEBUG) {
+ Slog.i(TAG, "Granting " + mPermission + " to user " + mUser.getIdentifier()
+ + " pkg=" + mPkgRequestingPerm.packageName + " granted=" + newGranted
+ + " flags=" + Integer.toBinaryString(newFlags));
+ }
+
+ int flagsToAdd = 0;
+ int flagsToRemove = 0;
+ if (newFlags != null) {
+ flagsToAdd = newFlags & ~mOriginalFlags;
+ flagsToRemove = mOriginalFlags & ~newFlags;
+ }
+
+ // Need to remove e.g. SYSTEM_FIXED flags first as otherwise permission cannot be
+ // changed
+ if (flagsToRemove != 0) {
+ NO_PM_CACHE.updatePermissionFlags(mPermission, mPkgRequestingPerm,
+ flagsToRemove, 0, mUser);
+ }
+
+ // Need to unrestrict first as otherwise permission grants might fail
+ if ((flagsToAdd & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
+ int newRestrictionExcemptFlags =
+ flagsToAdd & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
+
+ NO_PM_CACHE.updatePermissionFlags(mPermission,
+ mPkgRequestingPerm, newRestrictionExcemptFlags, -1, mUser);
+ }
+
+ if (newGranted != null && newGranted != mOriginalGranted) {
+ if (newGranted) {
+ NO_PM_CACHE.grantPermission(mPermission, mPkgRequestingPerm, mUser);
+ } else {
+ NO_PM_CACHE.revokePermission(mPermission, mPkgRequestingPerm, mUser);
+ }
+ }
+
+ if ((flagsToAdd & ~PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
+ int newFlags =
+ flagsToAdd & ~PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
+
+ NO_PM_CACHE.updatePermissionFlags(mPermission, mPkgRequestingPerm, newFlags,
+ -1, mUser);
+ }
+ }
+
+ /**
+ * Load the state of the flags before first use
+ */
+ void initFlags() {
+ if (newFlags == null) {
+ mOriginalFlags = NO_PM_CACHE.getPermissionFlags(mPermission, mPkgRequestingPerm,
+ mUser);
+ newFlags = mOriginalFlags;
+ }
+ }
+
+ /**
+ * Load the grant state before first use
+ */
+ void initGranted() {
+ if (newGranted == null) {
+ // Don't call NO_PM_CACHE here so that contexts are reused
+ mOriginalGranted = createContextAsUser(mUser).getPackageManager()
+ .checkPermission(mPermission, mPkgRequestingPerm.packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ newGranted = mOriginalGranted;
+ }
+ }
}
}
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 a18f90b..a967f3d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -149,6 +149,8 @@
import libcore.util.EmptyArray;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -388,7 +390,7 @@
Watchdog.getInstance().addThread(mHandler);
mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
- context, mHandlerThread.getLooper(), this);
+ context, mHandlerThread.getLooper());
SystemConfig systemConfig = SystemConfig.getInstance();
mSystemPermissions = systemConfig.getSystemPermissions();
mGlobalGids = systemConfig.getGlobalGids();
@@ -417,6 +419,11 @@
LocalServices.addService(PermissionManagerInternal.class, localService);
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.getSystemService(PermissionControllerManager.class).dump(fd, pw, args);
+ }
+
/**
* Creates and returns an initialized, internal service for use by other components.
* <p>
@@ -4639,11 +4646,11 @@
}
@Override
- public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
+ public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection) {
ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
- synchronized (PermissionManagerService.this.mLock) {
+ synchronized (mLock) {
int numTotalPermissions = mSettings.mPermissions.size();
for (int i = 0; i < numTotalPermissions; i++) {
@@ -4660,6 +4667,28 @@
}
@Override
+ public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ @PermissionInfo.ProtectionFlags int protectionFlags) {
+ ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+
+ synchronized (mLock) {
+ int numTotalPermissions = mSettings.mPermissions.size();
+
+ for (int i = 0; i < numTotalPermissions; i++) {
+ BasePermission bp = mSettings.mPermissions.valueAt(i);
+
+ if (bp.perm != null && (bp.perm.getProtectionFlags() & protectionFlags)
+ == protectionFlags) {
+ matchingPermissions.add(
+ PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
+ }
+ }
+ }
+
+ return matchingPermissions;
+ }
+
+ @Override
public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
return PermissionManagerService.this.backupRuntimePermissions(user);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 356d0ab..57a25ed 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -302,10 +302,14 @@
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
- /** Get all permission that have a certain protection level */
- public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
+ /** Get all permissions that have a certain protection */
+ public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection);
+ /** Get all permissions that have certain protection flags */
+ public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ @PermissionInfo.ProtectionFlags int protectionFlags);
+
/**
* Returns the delegate used to influence permission checking.
*
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 92184e8..341fadc 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -77,6 +77,7 @@
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -112,6 +113,15 @@
@GuardedBy("mLock")
private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
+ /**
+ * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently
+ * scheduled for a uid.
+ */
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray();
+
+ private List<String> mAppOpPermissions;
+
public PermissionPolicyService(@NonNull Context context) {
super(context);
@@ -122,7 +132,7 @@
public void onStart() {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService(
+ final PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
PermissionManagerServiceInternal.class);
final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -130,38 +140,44 @@
packageManagerInternal.getPackageList(new PackageListObserver() {
@Override
public void onPackageAdded(String packageName, int uid) {
- onPackageChanged(packageName, uid);
- }
-
- @Override
- public void onPackageChanged(String packageName, int uid) {
final int userId = UserHandle.getUserId(uid);
-
if (isStarted(userId)) {
synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
}
}
@Override
+ public void onPackageChanged(String packageName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ if (isStarted(userId)) {
+ synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
+ resetAppOpPermissionsIfNotRequestedForUid(uid);
+ }
+ }
+
+ @Override
public void onPackageRemoved(String packageName, int uid) {
- /* do nothing */
+ final int userId = UserHandle.getUserId(uid);
+ if (isStarted(userId)) {
+ resetAppOpPermissionsIfNotRequestedForUid(uid);
+ }
}
});
- permManagerInternal.addOnRuntimePermissionStateChangedListener(
+ permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
UserHandle.getUserId(uid));
+ resetAppOpPermissionsIfNotRequestedForUidAsync(uid);
}
};
final ArrayList<PermissionInfo> dangerousPerms =
- permManagerInternal.getAllPermissionWithProtection(
+ permissionManagerInternal.getAllPermissionsWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
-
try {
int numDangerousPerms = dangerousPerms.size();
for (int i = 0; i < numDangerousPerms; i++) {
@@ -184,6 +200,26 @@
Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
}
+ final List<PermissionInfo> appOpPermissionInfos =
+ permissionManagerInternal.getAllPermissionsWithProtectionFlags(
+ PermissionInfo.PROTECTION_FLAG_APPOP);
+ mAppOpPermissions = new ArrayList<>();
+ final int appOpPermissionInfosSize = appOpPermissionInfos.size();
+ for (int i = 0; i < appOpPermissionInfosSize; i++) {
+ final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i);
+
+ final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermissionInfo.name);
+ if (appOpCode != OP_NONE) {
+ mAppOpPermissions.add(appOpPermissionInfo.name);
+
+ try {
+ appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
+ } catch (RemoteException e) {
+ Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
+ }
+ }
+ }
+
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -323,7 +359,7 @@
// Force synchronization as permissions might have changed
synchronizePermissionsAndAppOpsForUser(userId);
- //restoreReadPhoneStatePermissions(userId);
+ restoreReadPhoneStatePermissions(userId);
// Tell observers we are initialized for this user.
if (callback != null) {
@@ -491,6 +527,70 @@
synchronizer.syncPackages();
}
+ private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) {
+ if (isStarted(UserHandle.getUserId(uid))) {
+ synchronized (mLock) {
+ if (!mIsUidSyncScheduled.get(uid)) {
+ mIsUidSyncScheduled.put(uid, true);
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
+ this, uid));
+ }
+ }
+ }
+ }
+
+ private void resetAppOpPermissionsIfNotRequestedForUid(int uid) {
+ synchronized (mLock) {
+ mIsUidSyncScheduled.delete(uid);
+ }
+
+ final Context context = getContext();
+ final PackageManager userPackageManager = getUserContext(context,
+ UserHandle.getUserHandleForUid(uid)).getPackageManager();
+ final String[] packageNames = userPackageManager.getPackagesForUid(uid);
+ if (packageNames == null || packageNames.length == 0) {
+ return;
+ }
+
+ final ArraySet<String> requestedPermissions = new ArraySet<>();
+ for (String packageName : packageNames) {
+ final PackageInfo packageInfo;
+ try {
+ packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ continue;
+ }
+ if (packageInfo == null || packageInfo.requestedPermissions == null) {
+ continue;
+ }
+ Collections.addAll(requestedPermissions, packageInfo.requestedPermissions);
+ }
+
+ final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+ final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService(
+ AppOpsManagerInternal.class);
+ final int appOpPermissionsSize = mAppOpPermissions.size();
+ for (int i = 0; i < appOpPermissionsSize; i++) {
+ final String appOpPermission = mAppOpPermissions.get(i);
+
+ if (!requestedPermissions.contains(appOpPermission)) {
+ final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission);
+ final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode);
+ for (String packageName : packageNames) {
+ final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid,
+ packageName);
+ if (appOpMode != defaultAppOpMode) {
+ appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid,
+ defaultAppOpMode, mAppOpsCallback);
+ appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid,
+ packageName, defaultAppOpMode, mAppOpsCallback);
+ }
+ }
+ }
+ }
+ }
+
/**
* Synchronizes permission to app ops. You *must* always sync all packages
* in a shared UID at the same time to ensure proper synchronization.
@@ -545,7 +645,7 @@
PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
PermissionManagerServiceInternal.class);
List<PermissionInfo> permissionInfos =
- permissionManagerInternal.getAllPermissionWithProtection(
+ permissionManagerInternal.getAllPermissionsWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
int permissionInfosSize = permissionInfos.size();
for (int i = 0; i < permissionInfosSize; i++) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2f84a99..3bc151a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1222,10 +1222,12 @@
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mPowerKeyHandled = true;
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
- "Power - Long Press - Global Actions");
- showGlobalActionsInternal();
+ if (!mPowerKeyHandled) {
+ mPowerKeyHandled = true;
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+ "Power - Long Press - Global Actions");
+ showGlobalActionsInternal();
+ }
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6726cc8..3336697 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -37,6 +37,9 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -791,13 +794,15 @@
}
// Get information about the package to be installed.
- PackageParser.PackageLite newPackage;
- try {
- newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
- } catch (PackageParser.PackageParserException e) {
- Slog.e(TAG, "Unable to parse new package", e);
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ ParseResult<PackageParser.ApkLite> parseResult = ApkLiteParseUtils.parseApkLite(
+ input.reset(), new File(session.resolvedBaseCodePath), 0);
+ if (parseResult.isError()) {
+ Slog.e(TAG, "Unable to parse new package: " + parseResult.getErrorMessage(),
+ parseResult.getException());
return false;
}
+ PackageParser.ApkLite newPackage = parseResult.getResult();
String packageName = newPackage.packageName;
Slog.i(TAG, "Enabling rollback for install of " + packageName
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 4bc7744..f4c77a0 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -783,15 +783,17 @@
@Override
public void onModuleDied() {
synchronized (SoundTriggerMiddlewareValidation.this) {
- try {
- mState = ModuleStatus.DEAD;
- mCallback.onModuleDied();
- } catch (RemoteException e) {
- // Dead client will be handled by binderDied() - no need to handle here.
- // In any case, client callbacks are considered best effort.
- Log.e(TAG, "Client callback exception.", e);
- }
+ mState = ModuleStatus.DEAD;
}
+ // Trigger the callback outside of the lock to avoid deadlocks.
+ try {
+ mCallback.onModuleDied();
+ } catch (RemoteException e) {
+ // Dead client will be handled by binderDied() - no need to handle here.
+ // In any case, client callbacks are considered best effort.
+ Log.e(TAG, "Client callback exception.", e);
+ }
+
}
@Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index d6390184..49c7819 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -35,8 +35,10 @@
import android.os.ServiceSpecificException;
import android.util.Log;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -166,12 +168,23 @@
}
@Override
- public synchronized void serviceDied(long cookie) {
+ public void serviceDied(long cookie) {
Log.w(TAG, String.format("Underlying HAL driver died."));
- for (Session session : mActiveSessions) {
- session.moduleDied();
+ List<ISoundTriggerCallback> callbacks = new ArrayList<>(mActiveSessions.size());
+ synchronized (this) {
+ for (Session session : mActiveSessions) {
+ callbacks.add(session.moduleDied());
+ }
+ reset();
}
- reset();
+ // Trigger the callbacks outside of the lock to avoid deadlocks.
+ for (ISoundTriggerCallback callback : callbacks) {
+ try {
+ callback.onModuleDied();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
/**
@@ -379,15 +392,13 @@
/**
* The underlying module HAL is dead.
+ * @return The client callback that needs to be invoked to notify the client.
*/
- private void moduleDied() {
- try {
- mCallback.onModuleDied();
- removeSession(this);
- mCallback = null;
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
+ private ISoundTriggerCallback moduleDied() {
+ ISoundTriggerCallback callback = mCallback;
+ removeSession(this);
+ mCallback = null;
+ return callback;
}
private void checkValid() {
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 373cb8b..3b4c423 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -21,7 +21,7 @@
import static android.app.usage.NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
-import static android.net.NetworkTemplate.getAllCollapsedRatTypes;
+import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.os.Debug.getIonHeapsSizeKb;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
@@ -30,6 +30,7 @@
import static android.util.MathUtils.constrain;
import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_TRUNCATE_TIMESTAMP;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -726,27 +727,25 @@
int atomTag, @NonNull List<StatsEvent> pulledData, boolean withFgbg) {
final NetworkTemplate template = NetworkTemplate.buildTemplateWifiWildcard();
final NetworkStats stats = getUidNetworkStatsSinceBoot(template, withFgbg);
- if (stats != null) {
- addNetworkStats(atomTag, pulledData, stats, withFgbg, 0 /* ratType */);
- return StatsManager.PULL_SUCCESS;
- }
- return StatsManager.PULL_SKIP;
+
+ // Return with PULL_SKIP to indicate there is an error.
+ if (stats == null) return StatsManager.PULL_SKIP;
+
+ addNetworkStats(atomTag, pulledData, stats, withFgbg, 0 /* ratType */);
+ return StatsManager.PULL_SUCCESS;
}
private int pullMobileBytesTransfer(
int atomTag, @NonNull List<StatsEvent> pulledData, boolean withFgbg) {
- int ret = StatsManager.PULL_SKIP;
- for (final int ratType : getAllCollapsedRatTypes()) {
- final NetworkTemplate template =
- NetworkTemplate.buildTemplateMobileWithRatType(null, ratType);
- final NetworkStats stats = getUidNetworkStatsSinceBoot(template, withFgbg);
- if (stats != null) {
- addNetworkStats(atomTag, pulledData, stats, withFgbg, ratType);
- ret = StatsManager.PULL_SUCCESS; // If any of them is not null, then success.
- }
- }
- // If there is no data return PULL_SKIP to avoid wasting performance adding empty stats.
- return ret;
+ final NetworkTemplate template =
+ NetworkTemplate.buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
+ final NetworkStats stats = getUidNetworkStatsSinceBoot(template, withFgbg);
+
+ // Return with PULL_SKIP to indicate there is an error.
+ if (stats == null) return StatsManager.PULL_SKIP;
+
+ addNetworkStats(atomTag, pulledData, stats, withFgbg, NETWORK_TYPE_ALL);
+ return StatsManager.PULL_SUCCESS;
}
private void addNetworkStats(int atomTag, @NonNull List<StatsEvent> ret,
@@ -757,6 +756,13 @@
stats.getValues(j, entry);
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
+ switch (atomTag) {
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
+ e.addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true);
+ break;
+ default:
+ }
e.writeInt(entry.uid);
e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
if (withFgbg) {
@@ -766,13 +772,6 @@
e.writeLong(entry.rxPackets);
e.writeLong(entry.txBytes);
e.writeLong(entry.txPackets);
- switch (atomTag) {
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
- e.writeInt(ratType);
- break;
- default:
- }
ret.add(e.build());
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 289bf66..4ba58bd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -665,12 +665,12 @@
@Override
public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, int sysUiSessionId) {
enforceBiometricDialog();
if (mBar != null) {
try {
mBar.showAuthenticationDialog(bundle, receiver, biometricModality,
- requireConfirmation, userId, opPackageName, operationId);
+ requireConfirmation, userId, opPackageName, operationId, sysUiSessionId);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 9a5b020..e675f4e 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -19,14 +19,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -39,6 +43,7 @@
import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.SystemTextClassifierMetadata;
@@ -69,6 +74,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
+import java.util.stream.Collectors;
/**
* A manager for TextClassifier services.
@@ -203,7 +209,7 @@
request.getSystemTextClassifierMetadata(),
/* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- service -> service.onClassifyText(sessionId, request, callback),
+ service -> service.onClassifyText(sessionId, request, wrap(callback)),
"onClassifyText",
callback);
}
@@ -235,7 +241,7 @@
handleRequest(
event.getSystemTextClassifierMetadata(),
/* verifyCallingPackage= */ true,
- /* attemptToBind= */ false,
+ /* attemptToBind= */ true,
service -> service.onSelectionEvent(sessionId, event),
"onSelectionEvent",
NO_OP_CALLBACK);
@@ -254,7 +260,7 @@
handleRequest(
systemTcMetadata,
/* verifyCallingPackage= */ true,
- /* attemptToBind= */ false,
+ /* attemptToBind= */ true,
service -> service.onTextClassifierEvent(sessionId, event),
"onTextClassifierEvent",
NO_OP_CALLBACK);
@@ -289,7 +295,8 @@
request.getSystemTextClassifierMetadata(),
/* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- service -> service.onSuggestConversationActions(sessionId, request, callback),
+ service -> service.onSuggestConversationActions(
+ sessionId, request, wrap(callback)),
"onSuggestConversationActions",
callback);
}
@@ -464,6 +471,10 @@
}
}
+ private static ITextClassifierCallback wrap(ITextClassifierCallback orig) {
+ return new CallbackWrapper(orig);
+ }
+
private void onTextClassifierServicePackageOverrideChanged(String overriddenPackage) {
synchronized (mLock) {
final int size = mUserStates.size();
@@ -1004,4 +1015,112 @@
onTextClassifierServicePackageOverrideChanged(currentServicePackageOverride);
}
}
+
+ /**
+ * Wraps an ITextClassifierCallback and modifies the response to it where necessary.
+ */
+ private static final class CallbackWrapper extends ITextClassifierCallback.Stub {
+
+ private final ITextClassifierCallback mWrapped;
+
+ CallbackWrapper(ITextClassifierCallback wrapped) {
+ mWrapped = Objects.requireNonNull(wrapped);
+ }
+
+ @Override
+ public void onSuccess(Bundle result) {
+ final Parcelable parcelled = TextClassifierService.getResponse(result);
+ if (parcelled instanceof TextClassification) {
+ rewriteTextClassificationIcons(result);
+ } else if (parcelled instanceof ConversationActions) {
+ rewriteConversationActionsIcons(result);
+ } else {
+ // do nothing.
+ }
+ try {
+ mWrapped.onSuccess(result);
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Callback error", e);
+ }
+ }
+
+ private static void rewriteTextClassificationIcons(Bundle result) {
+ final TextClassification classification = TextClassifierService.getResponse(result);
+ boolean rewrite = false;
+ for (RemoteAction action : classification.getActions()) {
+ rewrite |= shouldRewriteIcon(action);
+ }
+ if (rewrite) {
+ TextClassifierService.putResponse(
+ result,
+ classification.toBuilder()
+ .clearActions()
+ .addActions(classification.getActions()
+ .stream()
+ .map(action -> validAction(action))
+ .collect(Collectors.toList()))
+ .build());
+ }
+ }
+
+ private static void rewriteConversationActionsIcons(Bundle result) {
+ final ConversationActions convActions = TextClassifierService.getResponse(result);
+ boolean rewrite = false;
+ for (ConversationAction convAction : convActions.getConversationActions()) {
+ rewrite |= shouldRewriteIcon(convAction.getAction());
+ }
+ if (rewrite) {
+ TextClassifierService.putResponse(
+ result,
+ new ConversationActions(
+ convActions.getConversationActions()
+ .stream()
+ .map(convAction -> convAction.toBuilder()
+ .setAction(validAction(convAction.getAction()))
+ .build())
+ .collect(Collectors.toList()),
+ convActions.getId()));
+ }
+ }
+
+ @Nullable
+ private static RemoteAction validAction(@Nullable RemoteAction action) {
+ if (!shouldRewriteIcon(action)) {
+ return action;
+ }
+
+ final RemoteAction newAction = new RemoteAction(
+ changeIcon(action.getIcon()),
+ action.getTitle(),
+ action.getContentDescription(),
+ action.getActionIntent());
+ newAction.setEnabled(action.isEnabled());
+ newAction.setShouldShowIcon(action.shouldShowIcon());
+ return newAction;
+ }
+
+ private static boolean shouldRewriteIcon(@Nullable RemoteAction action) {
+ // Check whether to rewrite the icon.
+ // Rewrite icons to ensure that the icons do not:
+ // 1. Leak package names
+ // 2. are renderable in the client process.
+ return action != null && action.getIcon().getType() == Icon.TYPE_RESOURCE;
+ }
+
+ /** Changes icon of type=RESOURCES to icon of type=URI. */
+ private static Icon changeIcon(Icon icon) {
+ final Uri uri = IconsUriHelper.getInstance()
+ .getContentUri(icon.getResPackage(), icon.getResId());
+ return Icon.createWithContentUri(uri);
+ }
+
+ @Override
+ public void onFailure() {
+ try {
+ mWrapped.onFailure();
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Callback error", e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 8f71943..2314afc 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -46,6 +46,8 @@
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.TvStreamConfig;
+import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -179,7 +181,7 @@
Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
return;
}
- connection.resetLocked(null, null, null, null, null);
+ connection.resetLocked(null, null, null, null, null, null);
mConnections.remove(deviceId);
buildHardwareListLocked();
TvInputHardwareInfo info = connection.getHardwareInfoLocked();
@@ -369,25 +371,34 @@
if (callback == null) {
throw new NullPointerException();
}
+ TunerResourceManager trm = (TunerResourceManager) mContext.getSystemService(
+ Context.TV_TUNER_RESOURCE_MGR_SERVICE);
synchronized (mLock) {
Connection connection = mConnections.get(deviceId);
if (connection == null) {
Slog.e(TAG, "Invalid deviceId : " + deviceId);
return null;
}
- // TODO: check with TRM to compare the client's priority with the current holder's
- // priority. If lower, do nothing.
- if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) {
- TvInputHardwareImpl hardware =
- new TvInputHardwareImpl(connection.getHardwareInfoLocked());
- try {
- callback.asBinder().linkToDeath(connection, 0);
- } catch (RemoteException e) {
- hardware.release();
- return null;
- }
- connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId);
+
+ ResourceClientProfile profile =
+ new ResourceClientProfile(tvInputSessionId, priorityHint);
+ ResourceClientProfile holderProfile = connection.getResourceClientProfileLocked();
+ if (holderProfile != null && trm != null
+ && !trm.isHigherPriority(profile, holderProfile)) {
+ Slog.d(TAG, "Acquiring does not show higher priority than the current holder."
+ + " Device id:" + deviceId);
+ return null;
}
+ TvInputHardwareImpl hardware =
+ new TvInputHardwareImpl(connection.getHardwareInfoLocked());
+ try {
+ callback.asBinder().linkToDeath(connection, 0);
+ } catch (RemoteException e) {
+ hardware.release();
+ return null;
+ }
+ connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId,
+ profile);
return connection.getHardwareLocked();
}
}
@@ -411,7 +422,7 @@
if (callback != null) {
callback.asBinder().unlinkToDeath(connection, 0);
}
- connection.resetLocked(null, null, null, null, null);
+ connection.resetLocked(null, null, null, null, null, null);
}
}
@@ -621,6 +632,7 @@
private Integer mCallingUid = null;
private Integer mResolvedUserId = null;
private Runnable mOnFirstFrameCaptured;
+ private ResourceClientProfile mResourceClientProfile = null;
public Connection(TvInputHardwareInfo hardwareInfo) {
mHardwareInfo = hardwareInfo;
@@ -629,7 +641,8 @@
// *Locked methods assume TvInputHardwareManager.mLock is held.
public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback,
- TvInputInfo info, Integer callingUid, Integer resolvedUserId) {
+ TvInputInfo info, Integer callingUid, Integer resolvedUserId,
+ ResourceClientProfile profile) {
if (mHardware != null) {
try {
mCallback.onReleased();
@@ -644,6 +657,7 @@
mCallingUid = callingUid;
mResolvedUserId = resolvedUserId;
mOnFirstFrameCaptured = null;
+ mResourceClientProfile = profile;
if (mHardware != null && mCallback != null) {
try {
@@ -698,10 +712,14 @@
return mOnFirstFrameCaptured;
}
+ public ResourceClientProfile getResourceClientProfileLocked() {
+ return mResourceClientProfile;
+ }
+
@Override
public void binderDied() {
synchronized (mLock) {
- resetLocked(null, null, null, null, null);
+ resetLocked(null, null, null, null, null, null);
}
}
@@ -713,6 +731,7 @@
+ ", mConfigs: " + Arrays.toString(mConfigs)
+ ", mCallingUid: " + mCallingUid
+ ", mResolvedUserId: " + mResolvedUserId
+ + ", mResourceClientProfile: " + mResourceClientProfile
+ " }";
}
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 2f70840..41aa4ee 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.media.tv.TvInputManager;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -42,6 +44,7 @@
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -71,7 +74,8 @@
@GuardedBy("mLock")
private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();
- private TvInputManager mManager;
+ private TvInputManager mTvInputManager;
+ private ActivityManager mActivityManager;
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
// An internal resource request count to help generate resource handle.
@@ -94,7 +98,9 @@
if (!isForTesting) {
publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
}
- mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
+ mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
+ mActivityManager =
+ (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
mPriorityCongfig.parse();
}
@@ -204,7 +210,7 @@
@Override
public boolean requestDemux(@NonNull TunerDemuxRequest request,
- @NonNull int[] demuxHandle) throws RemoteException {
+ @NonNull int[] demuxHandle) throws RemoteException {
enforceTunerAccessPermission("requestDemux");
enforceTrmAccessPermission("requestDemux");
if (demuxHandle == null) {
@@ -362,14 +368,15 @@
@Override
public boolean isHigherPriority(
- ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile) {
+ ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile)
+ throws RemoteException {
enforceTrmAccessPermission("isHigherPriority");
- if (DEBUG) {
- Slog.d(TAG,
- "isHigherPriority(challengerProfile=" + challengerProfile
- + ", holderProfile=" + challengerProfile + ")");
+ if (challengerProfile == null || holderProfile == null) {
+ throw new RemoteException("Client profiles can't be null.");
}
- return true;
+ synchronized (mLock) {
+ return isHigherPriorityInternal(challengerProfile, holderProfile);
+ }
}
}
@@ -381,7 +388,7 @@
}
clientId[0] = INVALID_CLIENT_ID;
- if (mManager == null) {
+ if (mTvInputManager == null) {
Slog.e(TAG, "TvInputManager is null. Can't register client profile.");
return;
}
@@ -390,7 +397,7 @@
int pid = profile.getTvInputSessionId() == null
? Binder.getCallingPid() /*callingPid*/
- : mManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
+ : mTvInputManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
.tvInputSessionId(profile.getTvInputSessionId())
@@ -693,6 +700,33 @@
}
@VisibleForTesting
+ protected boolean isHigherPriorityInternal(ResourceClientProfile challengerProfile,
+ ResourceClientProfile holderProfile) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ "isHigherPriority(challengerProfile=" + challengerProfile
+ + ", holderProfile=" + challengerProfile + ")");
+ }
+ if (mTvInputManager == null) {
+ Slog.e(TAG, "TvInputManager is null. Can't compare the priority.");
+ // Allow the client to acquire the hardware interface
+ // when the TRM is not able to compare the priority.
+ return true;
+ }
+
+ int challengerPid = challengerProfile.getTvInputSessionId() == null
+ ? Binder.getCallingPid() /*callingPid*/
+ : mTvInputManager.getClientPid(challengerProfile.getTvInputSessionId()); /*tvAppId*/
+ int holderPid = holderProfile.getTvInputSessionId() == null
+ ? Binder.getCallingPid() /*callingPid*/
+ : mTvInputManager.getClientPid(holderProfile.getTvInputSessionId()); /*tvAppId*/
+
+ int challengerPriority = getClientPriority(challengerProfile.getUseCase(), challengerPid);
+ int holderPriority = getClientPriority(holderProfile.getUseCase(), holderPid);
+ return challengerPriority > holderPriority;
+ }
+
+ @VisibleForTesting
protected void releaseFrontendInternal(FrontendResource fe) {
if (DEBUG) {
Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ")");
@@ -818,8 +852,20 @@
@VisibleForTesting
protected boolean isForeground(int pid) {
- // TODO: how to get fg/bg information from pid
- return true;
+ if (mActivityManager == null) {
+ return false;
+ }
+ List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses();
+ if (appProcesses == null) {
+ return false;
+ }
+ for (RunningAppProcessInfo appProcess : appProcesses) {
+ if (appProcess.pid == pid
+ && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ return true;
+ }
+ }
+ return false;
}
private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
@@ -1044,7 +1090,7 @@
}
private void enforceTrmAccessPermission(String apiName) {
- getContext().enforceCallingPermission("android.permission.TUNER_RESOURCE_ACCESS",
+ getContext().enforceCallingOrSelfPermission("android.permission.TUNER_RESOURCE_ACCESS",
TAG + ": " + apiName);
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 6734ce7..72cdf4a 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -21,9 +21,8 @@
import static android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
-import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
-import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -1138,8 +1137,8 @@
targetHoldsPermission = false;
}
- final boolean basicGrant = (modeFlags & ~(FLAG_GRANT_READ_URI_PERMISSION
- | FLAG_GRANT_WRITE_URI_PERMISSION)) == 0;
+ final boolean basicGrant = (modeFlags
+ & (FLAG_GRANT_PERSISTABLE_URI_PERMISSION | FLAG_GRANT_PREFIX_URI_PERMISSION)) == 0;
if (basicGrant && targetHoldsPermission) {
// When caller holds permission, and this is a simple permission
// grant, we can skip generating any bookkeeping; when any advanced
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dcdbfded..850b657 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -104,7 +104,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_UNSET;
@@ -235,10 +234,8 @@
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.DestroyActivityItem;
import android.app.servertransaction.MoveToDisplayItem;
-import android.app.servertransaction.MultiWindowModeChangeItem;
import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.PauseActivityItem;
-import android.app.servertransaction.PipModeChangeItem;
import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.StartActivityItem;
import android.app.servertransaction.StopActivityItem;
@@ -573,7 +570,7 @@
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
- boolean mUseTransferredAnimation;
+ private boolean mUseTransferredAnimation;
/**
* @see #currentLaunchCanTurnScreenOn()
@@ -805,7 +802,7 @@
pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
pw.println(prefix + "mLastReportedConfigurations:");
- mLastReportedConfiguration.dump(pw, prefix + " ");
+ mLastReportedConfiguration.dump(pw, prefix + " ");
pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
if (!getRequestedOverrideConfiguration().equals(EMPTY)) {
@@ -841,7 +838,7 @@
pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
pw.print(" primaryColor=");
pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
- pw.print(prefix + " backgroundColor=");
+ pw.print(prefix); pw.print(" backgroundColor=");
pw.print(Integer.toHexString(taskDescription.getBackgroundColor()));
pw.print(" statusBarColor=");
pw.print(Integer.toHexString(taskDescription.getStatusBarColor()));
@@ -1155,11 +1152,6 @@
return;
}
- if (task.getStack().deferScheduleMultiWindowModeChanged()) {
- // Don't do anything if we are currently deferring multi-window mode change.
- return;
- }
-
// An activity is considered to be in multi-window mode if its task isn't fullscreen.
final boolean inMultiWindowMode = inMultiWindowMode();
if (inMultiWindowMode != mLastReportedMultiWindowMode) {
@@ -1167,20 +1159,19 @@
updatePictureInPictureMode(null, false);
} else {
mLastReportedMultiWindowMode = inMultiWindowMode;
- scheduleMultiWindowModeChanged(getConfiguration());
+ computeConfigurationAfterMultiWindowModeChange();
+ // If the activity is in stopping or stopped state, for instance, it's in the
+ // split screen task and not the top one, the last configuration it should keep
+ // is the one before multi-window mode change.
+ final ActivityState state = getState();
+ if (state != STOPPED && state != STOPPING) {
+ ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
+ true /* ignoreVisibility */);
+ }
}
}
}
- private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
- try {
- mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode, overrideConfig));
- } catch (Exception e) {
- // If process died, I don't care.
- }
- }
-
void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) {
if (task == null || task.getStack() == null || !attachedToProcess()) {
return;
@@ -1188,39 +1179,27 @@
final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
- // Picture-in-picture mode change normal triggers also multi-window mode change
- // except transitions between pip and split screen mode, so update that here in order.
- // Set the last reported MW state to the same as the PiP state since we haven't yet
- // actually resized the task (these callbacks need to proceed the configuration change
- // from the resize).
- // TODO(110009072): Once we move these callbacks to the client, remove all logic related
- // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
- final boolean shouldScheduleMultiWindowModeChange =
- mLastReportedMultiWindowMode != inMultiWindowMode();
+ // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
+ // update that here in order. Set the last reported MW state to the same as the PiP
+ // state since we haven't yet actually resized the task (these callbacks need to
+ // precede the configuration change from the resize.
mLastReportedPictureInPictureMode = inPictureInPictureMode;
mLastReportedMultiWindowMode = inPictureInPictureMode;
- final Configuration newConfig = new Configuration();
if (targetStackBounds != null && !targetStackBounds.isEmpty()) {
- newConfig.setTo(task.getRequestedOverrideConfiguration());
- Rect outBounds = newConfig.windowConfiguration.getBounds();
- task.adjustForMinimalTaskDimensions(outBounds, outBounds);
- task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration());
+ computeConfigurationAfterMultiWindowModeChange();
}
- schedulePictureInPictureModeChanged(newConfig);
- if (shouldScheduleMultiWindowModeChange) {
- scheduleMultiWindowModeChanged(newConfig);
- }
+ ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
+ true /* ignoreVisibility */);
}
}
- private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
- try {
- mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
- overrideConfig));
- } catch (Exception e) {
- // If process died, no one cares.
- }
+ private void computeConfigurationAfterMultiWindowModeChange() {
+ final Configuration newConfig = new Configuration();
+ newConfig.setTo(task.getRequestedOverrideConfiguration());
+ Rect outBounds = newConfig.windowConfiguration.getBounds();
+ final Configuration parentConfig = task.getParent().getConfiguration();
+ task.adjustForMinimalTaskDimensions(outBounds, outBounds, parentConfig);
+ task.computeConfigResourceOverrides(newConfig, parentConfig);
}
Task getTask() {
@@ -1609,13 +1588,9 @@
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- // b/35954083: Limit task affinity to uid to avoid various issues associated with sharing
- // affinity across uids.
- final String uid = Integer.toString(info.applicationInfo.uid);
- if (info.taskAffinity != null && !info.taskAffinity.startsWith(uid)) {
- info.taskAffinity = uid + ":" + info.taskAffinity;
- }
+ info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid);
taskAffinity = info.taskAffinity;
+ final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
&& !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
info.windowLayout.windowLayoutAffinity =
@@ -1673,6 +1648,22 @@
}
}
+ /**
+ * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid
+ * issues associated with sharing affinity across uids.
+ *
+ * @param affinity The affinity of the activity.
+ * @param uid The user-ID that has been assigned to this application.
+ * @return The task affinity with uid.
+ */
+ static String getTaskAffinityWithUid(String affinity, int uid) {
+ final String uidStr = Integer.toString(uid);
+ if (affinity != null && !affinity.startsWith(uidStr)) {
+ affinity = uidStr + ":" + affinity;
+ }
+ return affinity;
+ }
+
static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) {
int lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
if (aInfo.applicationInfo.isPrivilegedApp()
@@ -1906,13 +1897,7 @@
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
ActivityManager.TaskSnapshot snapshot) {
- if (getDisplayContent().mAppTransition.getAppTransition()
- == TRANSIT_DOCK_TASK_FROM_RECENTS) {
- // TODO(b/34099271): Remove this statement to add back the starting window and figure
- // out why it causes flickering, the starting window appears over the thumbnail while
- // the docked from recents transition occurs
- return STARTING_WINDOW_TYPE_NONE;
- } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
if (snapshotOrientationSameAsTask(snapshot) || (snapshot != null && fromRecents)) {
@@ -3387,12 +3372,14 @@
}
setClientVisible(fromActivity.mClientVisible);
- transferAnimation(fromActivity);
+ if (fromActivity.isAnimating()) {
+ transferAnimation(fromActivity);
- // When transferring an animation, we no longer need to apply an animation to the
- // the token we transfer the animation over. Thus, set this flag to indicate we've
- // transferred the animation.
- mUseTransferredAnimation = true;
+ // When transferring an animation, we no longer need to apply an animation to
+ // the token we transfer the animation over. Thus, set this flag to indicate
+ // we've transferred the animation.
+ mUseTransferredAnimation = true;
+ }
mWmService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
@@ -4531,6 +4518,15 @@
return false;
}
+ // Activity in a pinned stack should not be visible if the stack is in force hidden state.
+ // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the stack, which is a
+ // work around to send onStop before windowing mode change callbacks.
+ // See also ActivityStackSupervisor#removePinnedStackInSurfaceTransaction
+ // TODO: Should we ever be visible if the stack/task is invisible?
+ if (inPinnedWindowingMode() && stack.isForceHidden()) {
+ return false;
+ }
+
// Check if the activity is on a sleeping display, and if it can turn it ON.
if (getDisplay().isSleeping()) {
final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
@@ -4620,7 +4616,7 @@
// the current contract for "auto-Pip" is that the app should enter it before onPause
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
- && !isState(STOPPING, STOPPED, PAUSED);
+ && !isState(STARTED, STOPPING, STOPPED, PAUSED);
setDeferHidingClient(deferHidingClient);
setVisibility(false);
@@ -4631,9 +4627,16 @@
// activity is hidden
supportsEnterPipOnTaskSwitch = false;
break;
-
- case INITIALIZING:
case RESUMED:
+ // If the app is capable of entering PIP, we should try pausing it now
+ // so it can PIP correctly.
+ if (deferHidingClient) {
+ getRootTask().startPausingLocked(
+ mStackSupervisor.mUserLeaving /* userLeaving */,
+ false /* uiSleeping */, null /* resuming */);
+ break;
+ }
+ case INITIALIZING:
case PAUSING:
case PAUSED:
case STARTED:
@@ -5536,6 +5539,9 @@
// timeout should not be caused by this.
if (stopped) {
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
+ if (stack == null) {
+ return this;
+ }
// Try to use the one which is closest to top.
ActivityRecord r = stack.getResumedActivity();
if (r == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 2ab03ce..9df3f85 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -162,6 +162,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
/**
@@ -241,12 +242,6 @@
*/
boolean mInResumeTopActivity = false;
- private boolean mUpdateBoundsDeferred;
- private boolean mUpdateBoundsDeferredCalled;
- private boolean mUpdateDisplayedBoundsDeferredCalled;
- private final Rect mDeferredBounds = new Rect();
- private final Rect mDeferredDisplayedBounds = new Rect();
-
int mCurrentUser;
/** For comparison with DisplayContent bounds. */
@@ -845,58 +840,6 @@
return getDisplayContent();
}
- /**
- * Defers updating the bounds of the stack. If the stack was resized/repositioned while
- * deferring, the bounds will update in {@link #continueUpdateBounds()}.
- */
- void deferUpdateBounds() {
- if (!mUpdateBoundsDeferred) {
- mUpdateBoundsDeferred = true;
- mUpdateBoundsDeferredCalled = false;
- }
- }
-
- /**
- * Continues updating bounds after updates have been deferred. If there was a resize attempt
- * between {@link #deferUpdateBounds()} and {@link #continueUpdateBounds()}, the stack will
- * be resized to that bounds.
- */
- void continueUpdateBounds() {
- if (mUpdateBoundsDeferred) {
- mUpdateBoundsDeferred = false;
- if (mUpdateBoundsDeferredCalled) {
- setTaskBounds(mDeferredBounds);
- setBounds(mDeferredBounds);
- }
- }
- }
-
- private boolean updateBoundsAllowed(Rect bounds) {
- if (!mUpdateBoundsDeferred) {
- return true;
- }
- if (bounds != null) {
- mDeferredBounds.set(bounds);
- } else {
- mDeferredBounds.setEmpty();
- }
- mUpdateBoundsDeferredCalled = true;
- return false;
- }
-
- private boolean updateDisplayedBoundsAllowed(Rect bounds) {
- if (!mUpdateBoundsDeferred) {
- return true;
- }
- if (bounds != null) {
- mDeferredDisplayedBounds.set(bounds);
- } else {
- mDeferredDisplayedBounds.setEmpty();
- }
- mUpdateDisplayedBoundsDeferredCalled = true;
- return false;
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
final DisplayContent display = getDisplay();
@@ -1009,16 +952,6 @@
}
}
- boolean isTopActivityFocusable() {
- final ActivityRecord r = topRunningActivity();
- return r != null ? r.isFocusable()
- : (isFocusable() && getWindowConfiguration().canReceiveKeys());
- }
-
- boolean isFocusableAndVisible() {
- return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
- }
-
// TODO: Should each user have there own stacks?
@Override
void switchUser(int userId) {
@@ -1388,7 +1321,7 @@
boolean preserveWindows, boolean notifyClients) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
- mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
+ mStackSupervisor.beginActivityVisibilityUpdate();
try {
mEnsureActivitiesVisibleHelper.process(
starting, configChanges, preserveWindows, notifyClients);
@@ -1399,7 +1332,7 @@
notifyActivityDrawnLocked(null);
}
} finally {
- mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate();
+ mStackSupervisor.endActivityVisibilityUpdate();
}
}
@@ -1687,6 +1620,8 @@
ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
!PRESERVE_WINDOWS);
nothingToResume = shouldSleepActivities();
+ } else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) {
+ nothingToResume = false;
}
}
if (nothingToResume) {
@@ -2373,8 +2308,10 @@
boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
+
+ final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid());
if (srec == null || srec.getTask().affinity == null
- || !srec.getTask().affinity.equals(destAffinity)) {
+ || !srec.getTask().affinity.equals(affinity)) {
return true;
}
// Document-centric case: an app may be split in to multiple documents;
@@ -2676,9 +2613,9 @@
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
+ } else {
+ mRootWindowContainer.resumeFocusedStacksTopActivities();
}
-
- mRootWindowContainer.resumeFocusedStacksTopActivities();
return true;
}
@@ -2692,10 +2629,6 @@
// TODO: Can only be called from special methods in ActivityStackSupervisor.
// Need to consolidate those calls points into this resize method so anyone can call directly.
void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) {
- if (!updateBoundsAllowed(displayedBounds)) {
- return;
- }
-
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId());
mAtmService.deferWindowLayout();
try {
@@ -2735,10 +2668,6 @@
* basically resizes both stack and task bounds to the same bounds.
*/
private void setTaskBounds(Rect bounds) {
- if (!updateBoundsAllowed(bounds)) {
- return;
- }
-
final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds,
PooledLambda.__(Task.class), bounds);
forAllLeafTasks(c, true /* traverseTopToBottom */);
@@ -2802,67 +2731,91 @@
}
boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
- String dumpPackage, boolean needSep) {
- pw.println(" Stack #" + getRootTaskId()
- + ": type=" + activityTypeToString(getActivityType())
- + " mode=" + windowingModeToString(getWindowingMode()));
- pw.println(" isSleeping=" + shouldSleepActivities());
- pw.println(" mBounds=" + getRequestedOverrideBounds());
-
- boolean printed = dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
-
- needSep = printed;
- boolean pr = printThisActivity(pw, mPausingActivity, dumpPackage, needSep,
- " mPausingActivity: ");
- if (pr) {
- printed = true;
- needSep = false;
- }
- pr = printThisActivity(pw, getResumedActivity(), dumpPackage, needSep,
- " mResumedActivity: ");
- if (pr) {
- printed = true;
- needSep = false;
- }
- if (dumpAll) {
- pr = printThisActivity(pw, mLastPausedActivity, dumpPackage, needSep,
- " mLastPausedActivity: ");
- if (pr) {
- printed = true;
- needSep = true;
+ String dumpPackage, final boolean needSep) {
+ Runnable headerPrinter = () -> {
+ if (needSep) {
+ pw.println();
}
- printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage,
- needSep, " mLastNoHistoryActivity: ");
+ pw.println(" Stack #" + getRootTaskId()
+ + ": type=" + activityTypeToString(getActivityType())
+ + " mode=" + windowingModeToString(getWindowingMode()));
+ pw.println(" isSleeping=" + shouldSleepActivities());
+ pw.println(" mBounds=" + getRequestedOverrideBounds());
+ };
+
+ boolean printed = false;
+
+ if (dumpPackage == null) {
+ // If we are not filtering by package, we want to print absolutely everything,
+ // so always print the header even if there are no tasks/activities inside.
+ headerPrinter.run();
+ headerPrinter = null;
+ printed = true;
}
+
+ printed |= printThisActivity(pw, mPausingActivity, dumpPackage, false,
+ " mPausingActivity: ", null);
+ printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false,
+ " mResumedActivity: ", null);
+ if (dumpAll) {
+ printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
+ " mLastPausedActivity: ", null);
+ printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage,
+ false, " mLastNoHistoryActivity: ", null);
+ }
+
+ printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter);
+
return printed;
}
private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
- boolean dumpClient, String dumpPackage, boolean needSep) {
+ boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) {
if (!hasChild()) {
return false;
}
- final String prefix = " ";
+ final AtomicBoolean printedHeader = new AtomicBoolean(false);
+ final AtomicBoolean printed = new AtomicBoolean(false);
forAllLeafTasks((task) -> {
- if (needSep) {
- pw.println("");
+ final String prefix = " ";
+ Runnable headerPrinter = () -> {
+ printed.set(true);
+ if (!printedHeader.get()) {
+ if (needSep) {
+ pw.println("");
+ }
+ if (header != null) {
+ header.run();
+ }
+ printedHeader.set(true);
+ }
+ pw.print(prefix); pw.print("* "); pw.println(task);
+ pw.print(prefix); pw.print(" mBounds=");
+ pw.println(task.getRequestedOverrideBounds());
+ pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth);
+ pw.print(" mMinHeight="); pw.println(task.mMinHeight);
+ if (mLastNonFullscreenBounds != null) {
+ pw.print(prefix);
+ pw.print(" mLastNonFullscreenBounds=");
+ pw.println(task.mLastNonFullscreenBounds);
+ }
+ task.dump(pw, prefix + " ");
+ };
+ if (dumpPackage == null) {
+ // If we are not filtering by package, we want to print absolutely everything,
+ // so always print the header even if there are no activities inside.
+ headerPrinter.run();
+ headerPrinter = null;
}
- pw.println(prefix + "Task id #" + task.mTaskId);
- pw.println(prefix + "mBounds=" + task.getRequestedOverrideBounds());
- pw.println(prefix + "mMinWidth=" + task.mMinWidth);
- pw.println(prefix + "mMinHeight=" + task.mMinHeight);
- pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
- pw.println(prefix + "* " + task);
- task.dump(pw, prefix + " ");
final ArrayList<ActivityRecord> activities = new ArrayList<>();
// Add activities by traversing the hierarchy from bottom to top, since activities
// are dumped in reverse order in {@link ActivityStackSupervisor#dumpHistoryList()}.
task.forAllActivities((Consumer<ActivityRecord>) activities::add,
false /* traverseTopToBottom */);
dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
- dumpPackage, false, null, task);
+ dumpPackage, false, headerPrinter, task);
}, true /* traverseTopToBottom */);
- return true;
+ return printed.get();
}
ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -2932,8 +2885,8 @@
final int taskId = activity != null
? mStackSupervisor.getNextTaskIdForUser(activity.mUserId)
: mStackSupervisor.getNextTaskIdForUser();
- task = Task.create(
- mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
+ task = new ActivityStack(mAtmService, taskId, info, intent, voiceSession,
+ voiceInteractor, null /* taskDescription */, this);
// add the task to stack first, mTaskPositioner might need the stack association
addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
@@ -3344,23 +3297,6 @@
getDisplayContent().getPinnedStackController().setActions(actions);
}
- /**
- * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
- * bounds and we have a deferred PiP mode changed callback set with the animation.
- */
- public boolean deferScheduleMultiWindowModeChanged() {
- if (inPinnedWindowingMode()) {
- // For the pinned stack, the deferring of the multi-window mode changed is tied to the
- // transition animation into picture-in-picture, and is called once the animation
- // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
- // state.
- // @see BoundsAnimationController
- // @see BoundsAnimationControllerTests
- return (mBoundsAnimatingRequested || mBoundsAnimating);
- }
- return false;
- }
-
public boolean isForceScaled() {
return mBoundsAnimating;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index fe9e5f3c..fb7ba62 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -45,7 +45,6 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.TYPE_VIRTUAL;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
@@ -70,7 +69,6 @@
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_ONLY;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.RootWindowContainer.TAG_STATES;
@@ -126,7 +124,6 @@
import android.os.WorkSource;
import android.provider.MediaStore;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
@@ -332,11 +329,10 @@
PowerManager.WakeLock mGoingToSleepWakeLock;
/**
- * Temporary rect used during docked stack resize calculation so we don't need to create a new
- * object each time.
+ * Used to keep {@link RootWindowContainer#ensureActivitiesVisible} from being entered
+ * recursively. And only update keyguard states once the nested updates are done.
*/
- private final Rect tempRect = new Rect();
- private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
+ private int mVisibilityTransactionDepth;
private ActivityMetricsLogger mActivityMetricsLogger;
@@ -366,11 +362,6 @@
*/
boolean mAppVisibilitiesChangedSinceLastPause;
- /**
- * Set of tasks that are in resizing mode during an app transition to fill the "void".
- */
- private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();
-
private KeyguardController mKeyguardController;
private PowerManager mPowerManager;
@@ -784,6 +775,7 @@
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
+ proc.setLastActivityLaunchTime(r.lastLaunchTime);
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
@@ -915,6 +907,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
r.setState(PAUSED, "realStartActivityLocked");
+ mRootWindowContainer.executeAppTransitionForAllDisplay();
}
// Perform OOM scoring after the activity state is set, so the process can be updated with
// the latest state.
@@ -1092,8 +1085,7 @@
final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);
final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
- if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
- && displayOwnerUid != aInfo.applicationInfo.uid) {
+ if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID) {
// Limit launching on virtual displays, because their contents can be read from Surface
// by apps that created them.
if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
@@ -1416,29 +1408,6 @@
return mLaunchParamsController;
}
- private void deferUpdateRecentsHomeStackBounds() {
- mRootWindowContainer.deferUpdateBounds(ACTIVITY_TYPE_RECENTS);
- mRootWindowContainer.deferUpdateBounds(ACTIVITY_TYPE_HOME);
- }
-
- private void continueUpdateRecentsHomeStackBounds() {
- mRootWindowContainer.continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
- mRootWindowContainer.continueUpdateBounds(ACTIVITY_TYPE_HOME);
- }
-
- void notifyAppTransitionDone() {
- continueUpdateRecentsHomeStackBounds();
- for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
- final int taskId = mResizingTasksDuringAnimation.valueAt(i);
- final Task task =
- mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY);
- if (task != null) {
- task.setTaskDockedResizing(false);
- }
- }
- mResizingTasksDuringAnimation.clear();
- }
-
void setSplitScreenResizing(boolean resizing) {
if (resizing == mDockedStackResizing) {
return;
@@ -1452,16 +1421,15 @@
/**
* Workaround: Force-stop all the activities in the pinned stack before we reparent them
* to the fullscreen stack. This is to guarantee that when we are removing a stack,
- * that the client receives onStop() before it is reparented. We do this by detaching
- * the stack from the display so that it will be considered invisible when
- * ensureActivitiesVisible() is called, and all of its activities will be marked
- * invisible as well and added to the stopping list. After which we process the
+ * that the client receives onStop() before new windowing mode is set.
+ * We do this by detaching the stack from the display so that it will be considered
+ * invisible when ensureActivitiesVisible() is called, and all of its activities will be
+ * marked invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
stack.cancelAnimation();
stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
true /* processPausingActivities */, null /* configuration */);
@@ -1478,6 +1446,9 @@
toDisplay.getDefaultTaskDisplayArea().positionStackAtBottom(stack);
}
+ // Follow on the workaround: activities are kept force hidden till the new windowing
+ // mode is set.
+ stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mRootWindowContainer.resumeFocusedStacksTopActivities();
} finally {
@@ -1923,6 +1894,7 @@
pw.print(prefix);
pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
pw.println(prefix + "mUserStackInFront=" + mRootWindowContainer.mUserStackInFront);
+ pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
if (!mWaitingForActivityVisible.isEmpty()) {
pw.println(prefix + "mWaitingForActivityVisible=");
for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) {
@@ -1935,12 +1907,15 @@
}
static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage,
- boolean needSep, String prefix) {
+ boolean needSep, String prefix, Runnable header) {
if (activity != null) {
if (dumpPackage == null || dumpPackage.equals(activity.packageName)) {
if (needSep) {
pw.println();
}
+ if (header != null) {
+ header.run();
+ }
pw.print(prefix);
pw.println(activity);
return true;
@@ -1951,7 +1926,7 @@
static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
String prefix, String label, boolean complete, boolean brief, boolean client,
- String dumpPackage, boolean needNL, String header, Task lastTask) {
+ String dumpPackage, boolean needNL, Runnable header, Task lastTask) {
String innerPrefix = null;
String[] args = null;
boolean printed = false;
@@ -1971,7 +1946,7 @@
needNL = false;
}
if (header != null) {
- pw.println(header);
+ header.run();
header = null;
}
if (lastTask != r.getTask()) {
@@ -2242,12 +2217,6 @@
}
void scheduleUpdateMultiWindowMode(Task task) {
- // If the stack is animating in a way where we will be forcing a multi-mode change at the
- // end, then ensure that we defer all in between multi-window mode changes
- if (task.getStack().deferScheduleMultiWindowModeChanged()) {
- return;
- }
-
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityStackSupervisor::addToMultiWindowModeChangedList, this,
PooledLambda.__(ActivityRecord.class));
@@ -2314,6 +2283,24 @@
"android.server.am:TURN_ON:" + reason);
}
+ /** Starts a batch of visibility updates. */
+ void beginActivityVisibilityUpdate() {
+ mVisibilityTransactionDepth++;
+ }
+
+ /** Ends a batch of visibility updates. */
+ void endActivityVisibilityUpdate() {
+ mVisibilityTransactionDepth--;
+ if (mVisibilityTransactionDepth == 0) {
+ getKeyguardController().visibilitiesUpdated();
+ }
+ }
+
+ /** Returns {@code true} if the caller is on the path to update visibility. */
+ boolean inActivityVisibilityUpdate() {
+ return mVisibilityTransactionDepth > 0;
+ }
+
/**
* Begin deferring resume to avoid duplicate resumes in one pass.
*/
@@ -2454,16 +2441,6 @@
}
}
- /**
- * Puts a task into resizing mode during the next app transition.
- *
- * @param task The task to put into resizing mode
- */
- void setResizingDuringAnimation(Task task) {
- mResizingTasksDuringAnimation.add(task.mTaskId);
- task.setTaskDockedResizing(true);
- }
-
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
Task task = null;
@@ -2491,29 +2468,12 @@
mService.deferWindowLayout();
try {
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // Defer updating the stack in which recents is until the app transition is done, to
- // not run into issues where we still need to draw the task in recents but the
- // docked stack is already created.
- deferUpdateRecentsHomeStackBounds();
- // TODO(multi-display): currently recents animation only support default display.
- mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- // Unset launching windowing mode to prevent creating split-screen-primary stack
- // in RWC#anyTaskForId() below.
- activityOptions.setLaunchWindowingMode(WINDOWING_MODE_UNDEFINED);
- }
-
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
- continueUpdateRecentsHomeStackBounds();
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
- } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && task.getWindowingMode() != windowingMode) {
- mService.moveTaskToSplitScreenPrimaryTask(task, true /* toTop */);
}
if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -2562,12 +2522,6 @@
false /* validateIncomingUser */, null /* originatingPendingIntent */,
false /* allowBackgroundActivityStart */);
} finally {
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
- // If we are launching the task in the docked stack, put it into resizing mode so
- // the window renders full-screen with the background filling the void. Also only
- // call this at the end to make sure that tasks exists on the window manager side.
- setResizingDuringAnimation(task);
- }
mService.continueWindowLayout();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 7fad395..dfa3fe0 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -549,19 +549,28 @@
return mPendingRemoteAnimationRegistry;
}
- void dump(PrintWriter pw, String prefix, String dumpPackage) {
+ void dumpLastHomeActivityStartResult(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
pw.println(mLastHomeActivityStartResult);
+ }
- if (mLastHomeActivityStartRecord != null) {
+ void dump(PrintWriter pw, String prefix, String dumpPackage) {
+ boolean dumped = false;
+
+ final boolean dumpPackagePresent = dumpPackage != null;
+
+ if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent
+ || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) {
+ if (!dumped) {
+ dumped = true;
+ dumpLastHomeActivityStartResult(pw, prefix);
+ }
pw.print(prefix);
pw.println("mLastHomeActivityStartRecord:");
mLastHomeActivityStartRecord.dump(pw, prefix + " ", true /* dumpAll */);
}
- final boolean dumpPackagePresent = dumpPackage != null;
-
if (mLastStarter != null) {
final boolean dump = !dumpPackagePresent
|| mLastStarter.relatedToPackage(dumpPackage)
@@ -569,6 +578,10 @@
&& dumpPackage.equals(mLastHomeActivityStartRecord.packageName));
if (dump) {
+ if (!dumped) {
+ dumped = true;
+ dumpLastHomeActivityStartResult(pw, prefix);
+ }
pw.print(prefix);
mLastStarter.dump(pw, prefix + " ");
@@ -578,7 +591,7 @@
}
}
- if (dumpPackagePresent) {
+ if (!dumped) {
pw.print(prefix);
pw.println("(nothing)");
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4ea9902..79e8ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1125,7 +1125,7 @@
// If we are starting an activity that is not from the same uid as the currently resumed
// one, check whether app switches are allowed.
- if (voiceSession == null && (stack.getResumedActivity() == null
+ if (voiceSession == null && stack != null && (stack.getResumedActivity() == null
|| stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 4181f4b..d5df906 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -152,17 +152,6 @@
IVoiceInteractor mInteractor);
/**
- * Callback for window manager to let activity manager know that the app transition was
- * cancelled.
- */
- public abstract void notifyAppTransitionCancelled();
-
- /**
- * Callback for window manager to let activity manager know that the app transition is finished.
- */
- public abstract void notifyAppTransitionFinished();
-
- /**
* Returns the top activity from each of the currently visible stacks. The first entry will be
* the focused activity.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5220fb2..36caeec 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4036,36 +4036,8 @@
}
}
- @Override
- public boolean isInMultiWindowMode(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- return false;
- }
- // An activity is consider to be in multi-window mode if its task isn't fullscreen.
- return r.inMultiWindowMode();
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public boolean isInPictureInPictureMode(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- return isInPictureInPictureMode(ActivityRecord.forTokenLocked(token));
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- private boolean isInPictureInPictureMode(ActivityRecord r) {
+ @VisibleForTesting
+ boolean isInPictureInPictureMode(ActivityRecord r) {
return r != null
&& r.getRootTask() != null
&& r.inPinnedWindowingMode()
@@ -4954,7 +4926,7 @@
boolean printed = ActivityStackSupervisor.printThisActivity(pw,
mRootWindowContainer.getTopResumedActivity(), dumpPackage, needSep,
- " ResumedActivity: ");
+ " ResumedActivity: ", null);
if (printed) {
printedAnything = true;
needSep = false;
@@ -6107,20 +6079,6 @@
}
@Override
- public void notifyAppTransitionFinished() {
- synchronized (mGlobalLock) {
- mStackSupervisor.notifyAppTransitionDone();
- }
- }
-
- @Override
- public void notifyAppTransitionCancelled() {
- synchronized (mGlobalLock) {
- mStackSupervisor.notifyAppTransitionDone();
- }
- }
-
- @Override
public List<IBinder> getTopVisibleActivities() {
synchronized (mGlobalLock) {
return mRootWindowContainer.getTopVisibleActivities();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 654ccc8..67fe968 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -166,19 +166,13 @@
// done behind a dream window.
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
- final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
- final ActivityRecord animLpActivity = allowAnimations
- ? findAnimLayoutParamsToken(transit, activityTypes)
- : null;
- final ActivityRecord topOpeningApp = allowAnimations
- ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
- : null;
- final ActivityRecord topClosingApp = allowAnimations
- ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
- : null;
- final ActivityRecord topChangingApp = allowAnimations
- ? getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */)
- : null;
+ final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
+ final ActivityRecord topOpeningApp =
+ getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
+ final ActivityRecord topClosingApp =
+ getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
+ final ActivityRecord topChangingApp =
+ getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 1036af6..51357d1 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -23,11 +23,9 @@
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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.windowingModeToString;
@@ -391,8 +389,7 @@
public boolean inMultiWindowMode() {
/*@WindowConfiguration.WindowingMode*/ int windowingMode =
mFullConfiguration.windowConfiguration.getWindowingMode();
- return windowingMode != WINDOWING_MODE_FULLSCREEN
- && windowingMode != WINDOWING_MODE_UNDEFINED;
+ return WindowConfiguration.inMultiWindowMode(windowingMode);
}
/** Returns true if this container is currently in split-screen windowing mode. */
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c66ff33..5dd8e28 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -280,7 +280,8 @@
private final DisplayArea.Root mRootDisplayArea = new DisplayArea.Root(mWmService);
- private final DisplayAreaPolicy mDisplayAreaPolicy;
+ @VisibleForTesting
+ final DisplayAreaPolicy mDisplayAreaPolicy;
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
@@ -1392,6 +1393,13 @@
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
+ if (r != null && r.getTask() != null
+ && orientation != r.getTask().mLastReportedRequestedOrientation) {
+ final Task task = r.getTask();
+ task.mLastReportedRequestedOrientation = orientation;
+ mAtmService.getTaskChangeNotificationController()
+ .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
+ }
// Currently there is no use case from non-activity.
if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
// Display orientation should be deferred until the top fixed rotation is finished.
@@ -1612,9 +1620,7 @@
}
}
- // Announce rotation only if we will not animate as we already have the
- // windows in final state. Otherwise, we make this call at the rotation end.
- if (screenRotationAnimation == null && mWmService.mAccessibilityController != null) {
+ if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onRotationChangedLocked(this);
}
}
@@ -2539,6 +2545,9 @@
}
for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
final WindowState win = mTapExcludedWindows.get(i);
+ if (!win.isVisibleLw()) {
+ continue;
+ }
win.getTouchableRegion(mTmpRegion);
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
@@ -5233,25 +5242,13 @@
* the display naturally.
*/
private void applyRotationAndFinishFixedRotation(int oldRotation, int newRotation) {
- if (mFixedRotationLaunchingApp == null) {
+ final WindowToken rotatedLaunchingApp = mFixedRotationLaunchingApp;
+ if (rotatedLaunchingApp == null) {
applyRotation(oldRotation, newRotation);
return;
}
- // The display may be about to rotate seamlessly, and the animation of closing apps may
- // still animate in old rotation. So make sure the outdated animation won't show on the
- // rotated display.
- forAllActivities(a -> {
- if (a.nowVisible && a != mFixedRotationLaunchingApp
- && a.getWindowConfiguration().getRotation() != newRotation) {
- final WindowContainer<?> w = a.getAnimatingContainer();
- if (w != null) {
- w.cancelAnimation();
- }
- }
- });
-
- mFixedRotationLaunchingApp.finishFixedRotationTransform(
+ rotatedLaunchingApp.finishFixedRotationTransform(
() -> applyRotation(oldRotation, newRotation));
mFixedRotationLaunchingApp = null;
}
@@ -5639,6 +5636,11 @@
Slog.w(TAG, "Failed to deliver showInsets", e);
}
}
+
+ @Override
+ public boolean isClientControlled() {
+ return false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 8aace21..53b536c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -48,6 +48,7 @@
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -156,6 +157,7 @@
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InsetsFlags;
+import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.MotionEvent;
@@ -391,7 +393,8 @@
private boolean mDreamingLockscreen;
private boolean mAllowLockscreenWhenOn;
- private InputConsumer mInputConsumer = null;
+ @VisibleForTesting
+ InputConsumer mInputConsumer = null;
private PointerLocationView mPointerLocationView;
@@ -1372,13 +1375,6 @@
synchronized (mLock) {
mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
mDisplayContent.reevaluateStatusBarVisibility();
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL && mNavigationBar != null) {
- final InsetsControlTarget target =
- mNavigationBar.getControllableInsetProvider().getControlTarget();
- if (target != null) {
- target.showInsets(Type.navigationBars(), false /* fromIme */);
- }
- }
}
}
};
@@ -1406,6 +1402,7 @@
if (mInputConsumer == null) {
return;
}
+ showNavigationBar();
// Any user activity always causes us to show the
// navigation controls, if they had been hidden.
// We also clear the low profile and only content
@@ -1439,6 +1436,16 @@
finishInputEvent(event, false /* handled */);
}
}
+
+ private void showNavigationBar() {
+ final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
+ .peekSourceProvider(ITYPE_NAVIGATION_BAR);
+ final InsetsControlTarget target =
+ provider != null ? provider.getControlTarget() : null;
+ if (target != null) {
+ target.showInsets(Type.navigationBars(), false /* fromIme */);
+ }
+ }
}
private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
@@ -1500,9 +1507,13 @@
// drive nav being hidden only by whether it is requested.
final int sysui = mLastSystemUiFlags;
final int behavior = mLastBehavior;
+ final InsetsSourceProvider provider =
+ mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- : isNavigationBarRequestedVisible();
+ : provider != null
+ ? provider.isClientVisible()
+ : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
boolean navTranslucent = (sysui
& (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
@@ -1517,7 +1528,7 @@
&& (mNotificationShade.getAttrs().privateFlags
& PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
- updateHideNavInputEventReceiver(navVisible, navAllowedHidden);
+ updateHideNavInputEventReceiver();
// For purposes of positioning and showing the nav bar, if we have decided that it can't
// be hidden (because of the screen aspect ratio), then take that into account.
@@ -1539,30 +1550,38 @@
mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
}
- boolean isNavigationBarRequestedVisible() {
- final InsetsSourceProvider provider =
- mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
- return provider == null
- ? InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR)
- : provider.isClientVisible();
- }
-
- void updateHideNavInputEventReceiver(boolean navVisible, boolean navAllowedHidden) {
+ void updateHideNavInputEventReceiver() {
+ final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
+ .peekSourceProvider(ITYPE_NAVIGATION_BAR);
+ final InsetsControlTarget navControlTarget =
+ provider != null ? provider.getControlTarget() : null;
+ final WindowState navControllingWin =
+ navControlTarget instanceof WindowState ? (WindowState) navControlTarget : null;
+ final InsetsState requestedState = navControllingWin != null
+ ? navControllingWin.getRequestedInsetsState() : null;
+ final InsetsSource navSource = requestedState != null
+ ? requestedState.peekSource(ITYPE_NAVIGATION_BAR) : null;
+ final boolean navVisible = navSource != null
+ ? navSource.isVisible() : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ final boolean showBarsByTouch = navControllingWin != null
+ && navControllingWin.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_BARS_BY_TOUCH;
// When the navigation bar isn't visible, we put up a fake input window to catch all
// touch events. This way we can detect when the user presses anywhere to bring back the
// nav bar and ensure the application doesn't see the event.
- if (navVisible || navAllowedHidden) {
+ if (navVisible || !showBarsByTouch) {
if (mInputConsumer != null) {
mInputConsumer.dismiss();
mHandler.sendMessage(
mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
mInputConsumer = null;
+ Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " dismissed.");
}
} else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
mHandler.getLooper(),
INPUT_CONSUMER_NAVIGATION,
HideNavInputEventReceiver::new);
+ Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " created.");
// As long as mInputConsumer is active, hover events are not dispatched to the app
// and the pointer icon is likely to become stale. Hide it to avoid confusion.
InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
@@ -3135,16 +3154,6 @@
return 0;
}
- /**
- * Return true if it is okay to perform animations for an app transition
- * that is about to occur. You may return false for this if, for example,
- * the dream window is currently displayed so the switch should happen
- * immediately.
- */
- public boolean allowAppAnimationsLw() {
- return !mShowingDream;
- }
-
private void requestTransientBars(WindowState swipeTarget) {
if (!mService.mPolicy.isUserSetupComplete()) {
// Swipe-up for navigation bar is disabled during setup
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index bbc6c2b..42c1a07 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -61,4 +61,12 @@
default boolean canShowTransient() {
return false;
}
+
+ /**
+ * Returns {@code true} if the object controlling the insets is on client.
+ */
+ default boolean isClientControlled() {
+ return true;
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 5a9bf80..317bb43 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -25,7 +25,6 @@
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
@@ -95,13 +94,7 @@
|| focusedWin != getNavControlTarget(focusedWin)
|| focusedWin.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
.isVisible());
- updateHideNavInputEventReceiver();
- }
-
- private void updateHideNavInputEventReceiver() {
- mPolicy.updateHideNavInputEventReceiver(mPolicy.isNavigationBarRequestedVisible(),
- mFocusedWin != null
- && mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
+ mPolicy.updateHideNavInputEventReceiver();
}
boolean isHidden(@InternalInsetsType int type) {
@@ -201,7 +194,7 @@
if (windowState == getNavControlTarget(mFocusedWin)) {
mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
}
- updateHideNavInputEventReceiver();
+ mPolicy.updateHideNavInputEventReceiver();
}
/**
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 351743f..56986c2 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -38,6 +38,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.TriConsumer;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -288,6 +289,7 @@
t.deferTransactionUntil(leash, barrier, frameNumber);
}
mControlTarget = target;
+ updateVisibility();
mControl = new InsetsSourceControl(mSource.getType(), leash,
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
}
@@ -330,13 +332,16 @@
updateVisibility();
}
- private void setServerVisible(boolean serverVisible) {
+ @VisibleForTesting
+ void setServerVisible(boolean serverVisible) {
mServerVisible = serverVisible;
updateVisibility();
}
private void updateVisibility() {
- mSource.setVisible(mServerVisible && mClientVisible);
+ final boolean isClientControlled = mControlTarget != null
+ && mControlTarget.isClientControlled();
+ mSource.setVisible(mServerVisible && (!isClientControlled || mClientVisible));
}
InsetsSourceControl getControl(InsetsControlTarget target) {
@@ -408,10 +413,10 @@
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mAdapter == this) {
mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
- setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
mControl = null;
mControlTarget = null;
mAdapter = null;
+ setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index f672394..4c10d581 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -70,7 +70,6 @@
private boolean mKeyguardGoingAway;
private boolean mDismissalRequested;
private int mBeforeUnoccludeTransit;
- private int mVisibilityTransactionDepth;
private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
private final ActivityTaskManagerService mService;
private RootWindowContainer mRootWindowContainer;
@@ -252,24 +251,6 @@
}
/**
- * Starts a batch of visibility updates.
- */
- void beginActivityVisibilityUpdate() {
- mVisibilityTransactionDepth++;
- }
-
- /**
- * Ends a batch of visibility updates. After all batches are done, this method makes sure to
- * update lockscreen occluded/dismiss state if needed.
- */
- void endActivityVisibilityUpdate() {
- mVisibilityTransactionDepth--;
- if (mVisibilityTransactionDepth == 0) {
- visibilitiesUpdated();
- }
- }
-
- /**
* @return True if we may show an activity while Keyguard is showing because we are in the
* process of dismissing it anyways, false otherwise.
*/
@@ -292,7 +273,11 @@
&& !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
- private void visibilitiesUpdated() {
+ /**
+ * Makes sure to update lockscreen occluded/dismiss state if needed after completing all
+ * visibility updates ({@link ActivityStackSupervisor#endActivityVisibilityUpdate}).
+ */
+ void visibilitiesUpdated() {
boolean requestDismissKeyguard = false;
for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
@@ -568,7 +553,6 @@
pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
dumpDisplayStates(pw, prefix);
pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
- pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
pw.println();
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 09700c5..d8a4ecb 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1031,9 +1031,13 @@
void add(Task task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
+ // Only allow trimming task if it is not updating visibility for activities, so the caller
+ // doesn't need to handle unexpected size and index when looping task containers.
+ final boolean canTrimTask = !mSupervisor.inActivityVisibilityUpdate();
+
// Clean up the hidden tasks when going to home because the user may not be unable to return
// to the task from recents.
- if (!mHiddenTasks.isEmpty() && task.isActivityTypeHome()) {
+ if (canTrimTask && !mHiddenTasks.isEmpty() && task.isActivityTypeHome()) {
removeUnreachableHiddenTasks(task.getWindowingMode());
}
@@ -1155,7 +1159,9 @@
}
// Trim the set of tasks to the active set
- trimInactiveRecentTasks();
+ if (canTrimTask) {
+ trimInactiveRecentTasks();
+ }
notifyTaskPersisterLocked(task, false /* flush */);
}
@@ -1718,9 +1724,31 @@
final int size = mTasks.size();
for (int i = 0; i < size; i++) {
final Task task = mTasks.get(i);
- if (dumpPackage != null && (task.realActivity == null ||
- !dumpPackage.equals(task.realActivity.getPackageName()))) {
- continue;
+ if (dumpPackage != null) {
+ boolean match = task.intent != null
+ && task.intent.getComponent() != null
+ && dumpPackage.equals(
+ task.intent.getComponent().getPackageName());
+ if (!match) {
+ match |= task.affinityIntent != null
+ && task.affinityIntent.getComponent() != null
+ && dumpPackage.equals(
+ task.affinityIntent.getComponent().getPackageName());
+ }
+ if (!match) {
+ match |= task.origActivity != null
+ && dumpPackage.equals(task.origActivity.getPackageName());
+ }
+ if (!match) {
+ match |= task.realActivity != null
+ && dumpPackage.equals(task.realActivity.getPackageName());
+ }
+ if (!match) {
+ match |= dumpPackage.equals(task.mCallingPackage);
+ }
+ if (!match) {
+ continue;
+ }
}
if (!printedHeader) {
@@ -1743,6 +1771,31 @@
0, true /* getTasksAllowed */, mService.getCurrentUserId(), SYSTEM_UID);
for (int i = 0; i < tasks.size(); i++) {
final ActivityManager.RecentTaskInfo taskInfo = tasks.get(i);
+ if (dumpPackage != null) {
+ boolean match = taskInfo.baseIntent != null
+ && taskInfo.baseIntent.getComponent() != null
+ && dumpPackage.equals(
+ taskInfo.baseIntent.getComponent().getPackageName());
+ if (!match) {
+ match |= taskInfo.baseActivity != null
+ && dumpPackage.equals(taskInfo.baseActivity.getPackageName());
+ }
+ if (!match) {
+ match |= taskInfo.topActivity != null
+ && dumpPackage.equals(taskInfo.topActivity.getPackageName());
+ }
+ if (!match) {
+ match |= taskInfo.origActivity != null
+ && dumpPackage.equals(taskInfo.origActivity.getPackageName());
+ }
+ if (!match) {
+ match |= taskInfo.realActivity != null
+ && dumpPackage.equals(taskInfo.realActivity.getPackageName());
+ }
+ if (!match) {
+ continue;
+ }
+ }
if (!printedHeader) {
if (printedAnything) {
// Separate from the last block if it printed
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index dd761be..c96c664 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -421,16 +421,17 @@
@VisibleForTesting
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
- return addAnimation(task, isRecentTaskInvisible, null /* finishedCallback */);
+ return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
+ null /* finishedCallback */);
}
@VisibleForTesting
- AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible,
+ AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
OnAnimationFinishedCallback finishedCallback) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
isRecentTaskInvisible);
- task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */,
+ task.startAnimation(task.getPendingTransaction(), taskAdapter, hidden,
ANIMATION_TYPE_RECENTS, finishedCallback);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
@@ -530,7 +531,7 @@
final SparseBooleanArray recentTaskIds =
mService.mAtmService.getRecentTasks().getRecentTaskIds();
TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
- !recentTaskIds.get(task.mTaskId), finishedCallback);
+ !recentTaskIds.get(task.mTaskId), true /* hidden */, finishedCallback);
mPendingNewTaskTargets.add(task.mTaskId);
return adapter.createRemoteAnimationTarget();
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 77841dc..9a30f1c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -262,9 +262,6 @@
/** Set when a power hint has started, but not ended. */
private boolean mPowerHintSent;
- /** Used to keep ensureActivitiesVisible() from being entered recursively. */
- private boolean mInEnsureActivitiesVisible = false;
-
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
int mDefaultMinSizeOfResizeableTaskDp = -1;
@@ -1993,14 +1990,13 @@
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- if (mInEnsureActivitiesVisible) {
+ if (mStackSupervisor.inActivityVisibilityUpdate()) {
// Don't do recursive work.
return;
}
- mInEnsureActivitiesVisible = true;
try {
- mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
+ mStackSupervisor.beginActivityVisibilityUpdate();
// First the front stacks. In case any are not fullscreen and are in front of home.
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
@@ -2008,8 +2004,7 @@
notifyClients);
}
} finally {
- mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate();
- mInEnsureActivitiesVisible = false;
+ mStackSupervisor.endActivityVisibilityUpdate();
}
}
@@ -2509,20 +2504,6 @@
return list;
}
- void deferUpdateBounds(int activityType) {
- final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- stack.deferUpdateBounds();
- }
- }
-
- void continueUpdateBounds(int activityType) {
- final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- stack.continueUpdateBounds();
- }
- }
-
@Override
public void onDisplayAdded(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
@@ -3602,31 +3583,40 @@
boolean needSep = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
DisplayContent displayContent = getChildAt(displayNdx);
+ if (printed) {
+ pw.println();
+ }
pw.print("Display #"); pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- pw.println();
- printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
- needSep = printed;
+ if (needSep) {
+ pw.println();
+ }
+ needSep = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
+ printed |= needSep;
}
}
- pw.println(" (resumed activities in task display areas from top to bottom):");
for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
- printThisActivity(pw, taskDisplayArea.getFocusedActivity(), dumpPackage, needSep,
- " ResumedActivity:");
+ printed |= printThisActivity(pw, taskDisplayArea.getFocusedActivity(),
+ dumpPackage, needSep, " Resumed: ", () -> {
+ pw.println(" Resumed activities in task display areas"
+ + " (from top to bottom):");
+ });
}
}
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ",
"Fin", false, !dumpAll,
- false, dumpPackage, true, " Activities waiting to finish:", null);
+ false, dumpPackage, true,
+ () -> { pw.println(" Activities waiting to finish:"); }, null);
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ",
"Stop", false, !dumpAll,
- false, dumpPackage, true, " Activities waiting to stop:", null);
+ false, dumpPackage, true,
+ () -> { pw.println(" Activities waiting to stop:"); }, null);
return printed;
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 90936ef..14ab2e3 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -732,13 +732,6 @@
mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
kill();
mService.updateRotation(false, false);
- AccessibilityController accessibilityController = mService.mAccessibilityController;
-
- if (accessibilityController != null) {
- // We just finished rotation animation which means we did not
- // announce the rotation and waited for it to end, announce now.
- accessibilityController.onRotationChangedLocked(mDisplayContent);
- }
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 56147f2..bf20cb9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -679,10 +679,10 @@
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags) {
+ int flags, Region region) {
final long identity = Binder.clearCallingIdentity();
try {
- mService.updateInputChannel(channelToken, displayId, surface, flags);
+ mService.updateInputChannel(channelToken, displayId, surface, flags, region);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8f8ca77..caa0ddb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -82,7 +82,6 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -232,11 +231,6 @@
// Do not move the stack as a part of reparenting
static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
- /**
- * The factory used to create {@link Task}. This allows OEM subclass {@link Task}.
- */
- private static TaskFactory sTaskFactory;
-
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
@@ -368,6 +362,14 @@
@Surface.Rotation
private int mRotation;
+ /**
+ * Last requested orientation reported to DisplayContent. This is different from {@link
+ * #mOrientation} in the sense that this takes activities' requested orientation into
+ * account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need
+ * to notify for activities that don't specify any orientation.
+ */
+ int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
// For comparison with DisplayContent bounds.
private Rect mTmpRect = new Rect();
// For handling display rotations.
@@ -1822,22 +1824,16 @@
}
}
- void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
- final Rect parentBounds = getParent() != null ? getParent().getBounds() : null;
- if (bounds == null
- || (bounds.isEmpty() && (parentBounds == null || parentBounds.isEmpty()))) {
- return;
- }
+ void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
+ @NonNull Configuration parentConfig) {
int minWidth = mMinWidth;
int minHeight = mMinHeight;
// If the task has no requested minimal size, we'd like to enforce a minimal size
// so that the user can not render the task too small to manipulate. We don't need
// to do this for the pinned stack as the bounds are controlled by the system.
- if (!inPinnedWindowingMode() && getStack() != null) {
+ if (!inPinnedWindowingMode()) {
final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
- final DisplayContent display = getDisplayContent();
- final float density =
- (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
final int defaultMinSize = (int) (defaultMinSizeDp * density);
if (minWidth == INVALID_MIN_SIZE) {
@@ -1850,6 +1846,7 @@
if (bounds.isEmpty()) {
// If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
// do, we can just skip.
+ final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
return;
}
@@ -2015,7 +2012,7 @@
}
void updateSurfaceSize(SurfaceControl.Transaction transaction) {
- if (mSurfaceControl == null || mCreatedByOrganizer) {
+ if (mSurfaceControl == null || isOrganized()) {
return;
}
@@ -2444,12 +2441,13 @@
}
if (isLeafTask()) {
- resolveLeafOnlyOverrideConfigs(newParentConfig);
+ resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
}
computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
}
- void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig) {
+ private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
+ Rect previousBounds) {
int windowingMode =
getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2462,9 +2460,12 @@
computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
newParentConfig.windowConfiguration.getBounds(),
newParentConfig.orientation);
+ // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
+ // the parent or display is smaller than the size, the content may be cropped.
+ return;
}
- adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+ adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
if (windowingMode == WINDOWING_MODE_FREEFORM) {
// by policy, make sure the window remains within parent somewhere
final float density =
@@ -3057,15 +3058,6 @@
return mDragResizeMode;
}
- /**
- * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
- *
- * @param resizing Whether to put the task into drag resize mode.
- */
- public void setTaskDockedResizing(boolean resizing) {
- setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
- }
-
void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
if (displayContent == null) {
return;
@@ -3332,6 +3324,16 @@
});
}
+ boolean isTopActivityFocusable() {
+ final ActivityRecord r = topRunningActivity();
+ return r != null ? r.isFocusable()
+ : (isFocusable() && getWindowConfiguration().canReceiveKeys());
+ }
+
+ boolean isFocusableAndVisible() {
+ return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
+ }
+
void positionChildAtTop(ActivityRecord child) {
positionChildAt(child, POSITION_TOP);
}
@@ -3875,11 +3877,12 @@
pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
}
pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId());
- pw.print(prefix + "mHasBeenVisible=" + getHasBeenVisible());
- pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
- pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
- pw.print(" isResizeable=" + isResizeable());
- pw.print(" lastActiveTime=" + lastActiveTime);
+ pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible());
+ pw.print(prefix); pw.print("mResizeMode=");
+ pw.print(ActivityInfo.resizeModeToString(mResizeMode));
+ pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture);
+ pw.print(" isResizeable="); pw.println(isResizeable());
+ pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
}
@@ -4061,316 +4064,239 @@
}
}
- @VisibleForTesting
- static TaskFactory getTaskFactory() {
- if (sTaskFactory == null) {
- setTaskFactory(new TaskFactory());
- }
- return sTaskFactory;
- }
-
- static void setTaskFactory(TaskFactory factory) {
- sTaskFactory = factory;
- }
-
- static Task create(ActivityTaskManagerService service, int taskId, int activityType,
- ActivityInfo info, Intent intent, boolean createdByOrganizer) {
- return getTaskFactory().create(service, taskId, activityType, info, intent,
- createdByOrganizer);
- }
-
- static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor, ActivityStack stack) {
- return getTaskFactory().create(
- service, taskId, info, intent, voiceSession, voiceInteractor, stack);
- }
-
static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
throws IOException, XmlPullParserException {
- return getTaskFactory().restoreFromXml(in, stackSupervisor);
- }
+ Intent intent = null;
+ Intent affinityIntent = null;
+ ArrayList<ActivityRecord> activities = new ArrayList<>();
+ ComponentName realActivity = null;
+ boolean realActivitySuspended = false;
+ ComponentName origActivity = null;
+ String affinity = null;
+ String rootAffinity = null;
+ boolean hasRootAffinity = false;
+ String windowLayoutAffinity = null;
+ boolean rootHasReset = false;
+ boolean autoRemoveRecents = false;
+ boolean askedCompatMode = false;
+ int taskType = 0;
+ int userId = 0;
+ boolean userSetupComplete = true;
+ int effectiveUid = -1;
+ String lastDescription = null;
+ long lastTimeOnTop = 0;
+ boolean neverRelinquishIdentity = true;
+ int taskId = INVALID_TASK_ID;
+ final int outerDepth = in.getDepth();
+ TaskDescription taskDescription = new TaskDescription();
+ int taskAffiliation = INVALID_TASK_ID;
+ int taskAffiliationColor = 0;
+ int prevTaskId = INVALID_TASK_ID;
+ int nextTaskId = INVALID_TASK_ID;
+ int callingUid = -1;
+ String callingPackage = "";
+ String callingFeatureId = null;
+ int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+ boolean supportsPictureInPicture = false;
+ Rect lastNonFullscreenBounds = null;
+ int minWidth = INVALID_MIN_SIZE;
+ int minHeight = INVALID_MIN_SIZE;
+ int persistTaskVersion = 0;
- /**
- * A factory class used to create {@link Task} or its subclass if any. This can be
- * specified when system boots by setting it with
- * {@link #setTaskFactory(TaskFactory)}.
- */
- static class TaskFactory {
- Task create(ActivityTaskManagerService service, int taskId, int activityType,
- ActivityInfo info, Intent intent, boolean createdByOrganizer) {
- return new ActivityStack(service, taskId, activityType, info, intent,
- createdByOrganizer);
- }
-
- Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor, ActivityStack stack) {
- return new ActivityStack(service, taskId, info, intent, voiceSession, voiceInteractor,
- null /*taskDescription*/, stack);
- }
-
- /**
- * Should only be used when we're restoring {@link Task} from storage.
- */
- Task create(ActivityTaskManagerService service, int taskId, Intent intent,
- Intent affinityIntent, String affinity, String rootAffinity,
- ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
- boolean autoRemoveRecents, boolean askedCompatMode, int userId,
- int effectiveUid, String lastDescription,
- long lastTimeMoved, boolean neverRelinquishIdentity,
- TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
- int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- @Nullable String callingFeatureId, int resizeMode,
- boolean supportsPictureInPicture, boolean realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
- return new ActivityStack(service, taskId, intent, affinityIntent, affinity,
- rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
- askedCompatMode, userId, effectiveUid, lastDescription,
- lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
- prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
- callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
- userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
- null /*_voiceSession*/, null /*_voiceInteractor*/, stack);
- }
-
- Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
- throws IOException, XmlPullParserException {
- Intent intent = null;
- Intent affinityIntent = null;
- ArrayList<ActivityRecord> activities = new ArrayList<>();
- ComponentName realActivity = null;
- boolean realActivitySuspended = false;
- ComponentName origActivity = null;
- String affinity = null;
- String rootAffinity = null;
- boolean hasRootAffinity = false;
- String windowLayoutAffinity = null;
- boolean rootHasReset = false;
- boolean autoRemoveRecents = false;
- boolean askedCompatMode = false;
- int taskType = 0;
- int userId = 0;
- boolean userSetupComplete = true;
- int effectiveUid = -1;
- String lastDescription = null;
- long lastTimeOnTop = 0;
- boolean neverRelinquishIdentity = true;
- int taskId = INVALID_TASK_ID;
- final int outerDepth = in.getDepth();
- TaskDescription taskDescription = new TaskDescription();
- int taskAffiliation = INVALID_TASK_ID;
- int taskAffiliationColor = 0;
- int prevTaskId = INVALID_TASK_ID;
- int nextTaskId = INVALID_TASK_ID;
- int callingUid = -1;
- String callingPackage = "";
- String callingFeatureId = null;
- int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
- boolean supportsPictureInPicture = false;
- Rect lastNonFullscreenBounds = null;
- int minWidth = INVALID_MIN_SIZE;
- int minHeight = INVALID_MIN_SIZE;
- int persistTaskVersion = 0;
-
- for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
- final String attrName = in.getAttributeName(attrNdx);
- final String attrValue = in.getAttributeValue(attrNdx);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
- + attrName + " value=" + attrValue);
- switch (attrName) {
- case ATTR_TASKID:
- if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
- break;
- case ATTR_REALACTIVITY:
- realActivity = ComponentName.unflattenFromString(attrValue);
- break;
- case ATTR_REALACTIVITY_SUSPENDED:
- realActivitySuspended = Boolean.valueOf(attrValue);
- break;
- case ATTR_ORIGACTIVITY:
- origActivity = ComponentName.unflattenFromString(attrValue);
- break;
- case ATTR_AFFINITY:
- affinity = attrValue;
- break;
- case ATTR_ROOT_AFFINITY:
- rootAffinity = attrValue;
- hasRootAffinity = true;
- break;
- case ATTR_WINDOW_LAYOUT_AFFINITY:
- windowLayoutAffinity = attrValue;
- break;
- case ATTR_ROOTHASRESET:
- rootHasReset = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_AUTOREMOVERECENTS:
- autoRemoveRecents = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_ASKEDCOMPATMODE:
- askedCompatMode = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_USERID:
- userId = Integer.parseInt(attrValue);
- break;
- case ATTR_USER_SETUP_COMPLETE:
- userSetupComplete = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_EFFECTIVE_UID:
- effectiveUid = Integer.parseInt(attrValue);
- break;
- case ATTR_TASKTYPE:
- taskType = Integer.parseInt(attrValue);
- break;
- case ATTR_LASTDESCRIPTION:
- lastDescription = attrValue;
- break;
- case ATTR_LASTTIMEMOVED:
- lastTimeOnTop = Long.parseLong(attrValue);
- break;
- case ATTR_NEVERRELINQUISH:
- neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_TASK_AFFILIATION:
- taskAffiliation = Integer.parseInt(attrValue);
- break;
- case ATTR_PREV_AFFILIATION:
- prevTaskId = Integer.parseInt(attrValue);
- break;
- case ATTR_NEXT_AFFILIATION:
- nextTaskId = Integer.parseInt(attrValue);
- break;
- case ATTR_TASK_AFFILIATION_COLOR:
- taskAffiliationColor = Integer.parseInt(attrValue);
- break;
- case ATTR_CALLING_UID:
- callingUid = Integer.parseInt(attrValue);
- break;
- case ATTR_CALLING_PACKAGE:
- callingPackage = attrValue;
- break;
- case ATTR_CALLING_FEATURE_ID:
- callingFeatureId = attrValue;
- break;
- case ATTR_RESIZE_MODE:
- resizeMode = Integer.parseInt(attrValue);
- break;
- case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
- supportsPictureInPicture = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_NON_FULLSCREEN_BOUNDS:
- lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
- break;
- case ATTR_MIN_WIDTH:
- minWidth = Integer.parseInt(attrValue);
- break;
- case ATTR_MIN_HEIGHT:
- minHeight = Integer.parseInt(attrValue);
- break;
- case ATTR_PERSIST_TASK_VERSION:
- persistTaskVersion = Integer.parseInt(attrValue);
- break;
- default:
- if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
- Slog.w(TAG, "Task: Unknown attribute=" + attrName);
- }
- }
+ for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+ final String attrName = in.getAttributeName(attrNdx);
+ final String attrValue = in.getAttributeValue(attrNdx);
+ if (TaskPersister.DEBUG) {
+ Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value="
+ + attrValue);
}
- taskDescription.restoreFromXml(in);
-
- int event;
- while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
- && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
- if (event == XmlPullParser.START_TAG) {
- final String name = in.getName();
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
- "Task: START_TAG name=" + name);
- if (TAG_AFFINITYINTENT.equals(name)) {
- affinityIntent = Intent.restoreFromXml(in);
- } else if (TAG_INTENT.equals(name)) {
- intent = Intent.restoreFromXml(in);
- } else if (TAG_ACTIVITY.equals(name)) {
- ActivityRecord activity =
- ActivityRecord.restoreFromXml(in, stackSupervisor);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
- + activity);
- if (activity != null) {
- activities.add(activity);
- }
- } else {
- handleUnknownTag(name, in);
+ switch (attrName) {
+ case ATTR_TASKID:
+ if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_REALACTIVITY:
+ realActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_REALACTIVITY_SUSPENDED:
+ realActivitySuspended = Boolean.valueOf(attrValue);
+ break;
+ case ATTR_ORIGACTIVITY:
+ origActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_AFFINITY:
+ affinity = attrValue;
+ break;
+ case ATTR_ROOT_AFFINITY:
+ rootAffinity = attrValue;
+ hasRootAffinity = true;
+ break;
+ case ATTR_WINDOW_LAYOUT_AFFINITY:
+ windowLayoutAffinity = attrValue;
+ break;
+ case ATTR_ROOTHASRESET:
+ rootHasReset = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_AUTOREMOVERECENTS:
+ autoRemoveRecents = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_ASKEDCOMPATMODE:
+ askedCompatMode = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_USERID:
+ userId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_USER_SETUP_COMPLETE:
+ userSetupComplete = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_EFFECTIVE_UID:
+ effectiveUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASKTYPE:
+ taskType = Integer.parseInt(attrValue);
+ break;
+ case ATTR_LASTDESCRIPTION:
+ lastDescription = attrValue;
+ break;
+ case ATTR_LASTTIMEMOVED:
+ lastTimeOnTop = Long.parseLong(attrValue);
+ break;
+ case ATTR_NEVERRELINQUISH:
+ neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION:
+ taskAffiliation = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PREV_AFFILIATION:
+ prevTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_NEXT_AFFILIATION:
+ nextTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION_COLOR:
+ taskAffiliationColor = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_UID:
+ callingUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_PACKAGE:
+ callingPackage = attrValue;
+ break;
+ case ATTR_CALLING_FEATURE_ID:
+ callingFeatureId = attrValue;
+ break;
+ case ATTR_RESIZE_MODE:
+ resizeMode = Integer.parseInt(attrValue);
+ break;
+ case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
+ supportsPictureInPicture = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_NON_FULLSCREEN_BOUNDS:
+ lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
+ break;
+ case ATTR_MIN_WIDTH:
+ minWidth = Integer.parseInt(attrValue);
+ break;
+ case ATTR_MIN_HEIGHT:
+ minHeight = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PERSIST_TASK_VERSION:
+ persistTaskVersion = Integer.parseInt(attrValue);
+ break;
+ default:
+ if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
+ Slog.w(TAG, "Task: Unknown attribute=" + attrName);
}
- }
}
- if (!hasRootAffinity) {
- rootAffinity = affinity;
- } else if ("@".equals(rootAffinity)) {
- rootAffinity = null;
- }
- if (effectiveUid <= 0) {
- Intent checkIntent = intent != null ? intent : affinityIntent;
- effectiveUid = 0;
- if (checkIntent != null) {
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- ApplicationInfo ai = pm.getApplicationInfo(
- checkIntent.getComponent().getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
- if (ai != null) {
- effectiveUid = ai.uid;
- }
- } catch (RemoteException e) {
+ }
+ taskDescription.restoreFromXml(in);
+
+ int event;
+ while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
+ && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
+ if (event == XmlPullParser.START_TAG) {
+ final String name = in.getName();
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name);
+ if (TAG_AFFINITYINTENT.equals(name)) {
+ affinityIntent = Intent.restoreFromXml(in);
+ } else if (TAG_INTENT.equals(name)) {
+ intent = Intent.restoreFromXml(in);
+ } else if (TAG_ACTIVITY.equals(name)) {
+ ActivityRecord activity =
+ ActivityRecord.restoreFromXml(in, stackSupervisor);
+ if (TaskPersister.DEBUG) {
+ Slog.d(TaskPersister.TAG, "Task: activity=" + activity);
}
- }
- Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
- + ": effectiveUid=" + effectiveUid);
- }
-
- if (persistTaskVersion < 1) {
- // We need to convert the resize mode of home activities saved before version one if
- // they are marked as RESIZE_MODE_RESIZEABLE to
- // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
- // before version 1 and the system didn't resize home activities before then.
- if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
- resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
- }
- } else {
- // This activity has previously marked itself explicitly as both resizeable and
- // supporting picture-in-picture. Since there is no longer a requirement for
- // picture-in-picture activities to be resizeable, we can mark this simply as
- // resizeable and supporting picture-in-picture separately.
- if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
- resizeMode = RESIZE_MODE_RESIZEABLE;
- supportsPictureInPicture = true;
+ if (activity != null) {
+ activities.add(activity);
+ }
+ } else {
+ Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+ XmlUtils.skipCurrentTag(in);
}
}
-
- final Task task = create(stackSupervisor.mService,
- taskId, intent, affinityIntent,
- affinity, rootAffinity, realActivity, origActivity, rootHasReset,
- autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
- lastTimeOnTop, neverRelinquishIdentity, taskDescription,
- taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
- callingPackage, callingFeatureId, resizeMode, supportsPictureInPicture,
- realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*stack*/);
- task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
- task.setBounds(lastNonFullscreenBounds);
- task.mWindowLayoutAffinity = windowLayoutAffinity;
-
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- task.addChild(activities.get(activityNdx));
+ }
+ if (!hasRootAffinity) {
+ rootAffinity = affinity;
+ } else if ("@".equals(rootAffinity)) {
+ rootAffinity = null;
+ }
+ if (effectiveUid <= 0) {
+ Intent checkIntent = intent != null ? intent : affinityIntent;
+ effectiveUid = 0;
+ if (checkIntent != null) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(
+ checkIntent.getComponent().getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ if (ai != null) {
+ effectiveUid = ai.uid;
+ }
+ } catch (RemoteException e) {
+ }
}
-
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
- return task;
+ Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
+ + ": effectiveUid=" + effectiveUid);
}
- void handleUnknownTag(String name, XmlPullParser in)
- throws IOException, XmlPullParserException {
- Slog.e(TAG, "restoreTask: Unexpected name=" + name);
- XmlUtils.skipCurrentTag(in);
+ if (persistTaskVersion < 1) {
+ // We need to convert the resize mode of home activities saved before version one if
+ // they are marked as RESIZE_MODE_RESIZEABLE to
+ // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
+ // before version 1 and the system didn't resize home activities before then.
+ if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
+ resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+ }
+ } else {
+ // This activity has previously marked itself explicitly as both resizeable and
+ // supporting picture-in-picture. Since there is no longer a requirement for
+ // picture-in-picture activities to be resizeable, we can mark this simply as
+ // resizeable and supporting picture-in-picture separately.
+ if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
+ resizeMode = RESIZE_MODE_RESIZEABLE;
+ supportsPictureInPicture = true;
+ }
}
+
+ final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent,
+ affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
+ autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
+ lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation,
+ prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
+ callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
+ userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
+ null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */);
+ task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
+ task.setBounds(lastNonFullscreenBounds);
+ task.mWindowLayoutAffinity = windowLayoutAffinity;
+
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ task.addChild(activities.get(activityNdx));
+ }
+
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
+ return task;
}
@Override
@@ -4626,7 +4552,14 @@
if (mForceHiddenFlags == newFlags) {
return false;
}
+ final boolean wasHidden = isForceHidden();
mForceHiddenFlags = newFlags;
+ if (wasHidden && isFocusableAndVisible()) {
+ // The change in force-hidden state will change visibility without triggering a stack
+ // order change, so we should reset the preferred top focusable stack to ensure it's not
+ // used if a new activity is started from this task.
+ getDisplayArea().resetPreferredTopFocusableStackIfBelow(this);
+ }
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 4b0e293..df0fa9c 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -60,6 +60,7 @@
private static final int NOTIFY_SINGLE_TASK_DISPLAY_EMPTY = 25;
private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
private static final int NOTIFY_TASK_FOCUS_CHANGED_MSG = 27;
+ private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 28;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -178,6 +179,10 @@
l.onTaskFocusChanged(m.arg1, m.arg2 != 0);
};
+ private final TaskStackConsumer mNotifyTaskRequestedOrientationChanged = (l, m) -> {
+ l.onTaskRequestedOrientationChanged(m.arg1, m.arg2);
+ };
+
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -269,6 +274,9 @@
case NOTIFY_TASK_FOCUS_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
break;
+ case NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG:
+ forAllRemoteListeners(mNotifyTaskRequestedOrientationChanged, msg);
+ break;
}
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
@@ -558,4 +566,12 @@
forAllLocalListeners(mNotifyTaskFocusChanged, msg);
msg.sendToTarget();
}
+
+ /** @see android.app.ITaskStackListener#onTaskRequestedOrientationChanged(int, int) */
+ void notifyTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG,
+ taskId, requestedOrientation);
+ forAllLocalListeners(mNotifyTaskRequestedOrientationChanged, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 3dc6723..0a1ee2b 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -680,6 +680,13 @@
onStackOrderChanged(stack);
}
+ void resetPreferredTopFocusableStackIfBelow(Task task) {
+ if (mPreferredTopFocusableStack != null
+ && mPreferredTopFocusableStack.compareTo(task) < 0) {
+ mPreferredTopFocusableStack = null;
+ }
+ }
+
void positionStackAt(int position, ActivityStack child, boolean includingParents) {
positionChildAt(position, child, includingParents);
mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
@@ -959,7 +966,7 @@
windowingMode = WINDOWING_MODE_UNDEFINED;
}
- final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
+ final ActivityStack stack = new ActivityStack(mAtmService, stackId, activityType,
info, intent, createdByOrganizer);
if (launchRootTask != null) {
launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 79baab6..06c2b16 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -48,6 +48,16 @@
mDisplayContent = displayContent;
}
+ private void restorePointerIcon(int x, int y) {
+ if (mPointerIconType != TYPE_NOT_SPECIFIED) {
+ mPointerIconType = TYPE_NOT_SPECIFIED;
+ // Find the underlying window and ask it to restore the pointer icon.
+ mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
+ mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
+ x, y, mDisplayContent).sendToTarget();
+ }
+ }
+
@Override
public void onPointerEvent(MotionEvent motionEvent) {
switch (motionEvent.getActionMasked()) {
@@ -67,6 +77,10 @@
case MotionEvent.ACTION_HOVER_MOVE: {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
+ if (mTouchExcludeRegion.contains(x, y)) {
+ restorePointerIcon(x, y);
+ break;
+ }
final Task task = mDisplayContent.findTaskForResizePoint(x, y);
int iconType = TYPE_NOT_SPECIFIED;
if (task != null) {
@@ -103,13 +117,7 @@
case MotionEvent.ACTION_HOVER_EXIT: {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
- if (mPointerIconType != TYPE_NOT_SPECIFIED) {
- mPointerIconType = TYPE_NOT_SPECIFIED;
- // Find the underlying window and ask it to restore the pointer icon.
- mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
- mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
- x, y, mDisplayContent).sendToTarget();
- }
+ restorePointerIcon(x, y);
}
break;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 5f3c633..132d00a 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -123,19 +123,20 @@
}
final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
- if (visible) {
- final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
+ if (visible && wallpaperTarget != null) {
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
- if (wallpaperTarget != null
- && recentsAnimationController != null
+ if (recentsAnimationController != null
&& recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) {
// If the Recents animation is running, and the wallpaper target is the animating
// task we want the wallpaper to be rotated in the same orientation as the
// RecentsAnimation's target (e.g the launcher)
recentsAnimationController.linkFixedRotationTransformIfNeeded(this);
- } else if (wallpaperTarget != null
+ } else if ((wallpaperTarget.mActivityRecord == null
+ // Ignore invisible activity because it may be moving to background.
+ || wallpaperTarget.mActivityRecord.mVisibleRequested)
&& wallpaperTarget.mToken.hasFixedRotationTransform()) {
// If the wallpaper target has a fixed rotation, we want the wallpaper to follow its
// rotation
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 84d749f..814fa72 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -72,6 +72,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManagerGlobal.ADD_OKAY;
@@ -195,6 +196,7 @@
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
+import android.sysprop.SurfaceFlingerProperties;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -304,7 +306,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -926,8 +930,14 @@
}
void updateFixedRotationTransform() {
- mIsFixedRotationTransformEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
+ final int enabled = Settings.Global.getInt(mContext.getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 2);
+ if (enabled == 2) {
+ // Make sure who read the settings won't use inconsistent default value.
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 1);
+ }
+ mIsFixedRotationTransformEnabled = enabled != 0;
}
}
@@ -1057,12 +1067,10 @@
@Override
public void onAppTransitionCancelledLocked(int transit) {
- mAtmInternal.notifyAppTransitionCancelled();
}
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
- mAtmInternal.notifyAppTransitionFinished();
final ActivityRecord atoken = mRoot.getActivityRecord(token);
if (atoken == null) {
return;
@@ -1367,6 +1375,7 @@
case TYPE_NOTIFICATION_SHADE:
case TYPE_NAVIGATION_BAR:
case TYPE_INPUT_METHOD_DIALOG:
+ case TYPE_VOLUME_OVERLAY:
return true;
}
return false;
@@ -4686,6 +4695,11 @@
}
private static boolean queryWideColorGamutSupport() {
+ boolean defaultValue = false;
+ Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display();
+ if (hasWideColorProp.isPresent()) {
+ return hasWideColorProp.get();
+ }
try {
ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
OptionalBool hasWideColor = surfaceFlinger.hasWideColorDisplay();
@@ -4694,11 +4708,18 @@
}
} catch (RemoteException e) {
// Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store
+ } catch (NoSuchElementException e) {
+ return defaultValue;
}
return false;
}
private static boolean queryHdrSupport() {
+ boolean defaultValue = false;
+ Optional<Boolean> hasHdrProp = SurfaceFlingerProperties.has_HDR_display();
+ if (hasHdrProp.isPresent()) {
+ return hasHdrProp.get();
+ }
try {
ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
OptionalBool hasHdr = surfaceFlinger.hasHDRDisplay();
@@ -4707,6 +4728,8 @@
}
} catch (RemoteException e) {
// Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store
+ } catch (NoSuchElementException e) {
+ return defaultValue;
}
return false;
}
@@ -7970,17 +7993,24 @@
handleTaskFocusChange(touchedWindow.getTask());
}
- private void handleTaskFocusChange(Task task) {
+ @VisibleForTesting
+ void handleTaskFocusChange(Task task) {
if (task == null) {
return;
}
- final ActivityStack stack = task.getStack();
// We ignore home stack since we don't want home stack to move to front when touched.
// Specifically, in freeform we don't want tapping on home to cause the freeform apps to go
// behind home. See b/117376413
- if (stack.isActivityTypeHome()) {
- return;
+ if (task.isActivityTypeHome()) {
+ // Only ignore home stack if the requested focus home Task is in the same
+ // TaskDisplayArea as the current focus Task.
+ TaskDisplayArea homeTda = task.getDisplayArea();
+ WindowState curFocusedWindow = getFocusedWindow();
+ if (curFocusedWindow != null && homeTda != null
+ && curFocusedWindow.isDescendantOf(homeTda)) {
+ return;
+ }
}
try {
@@ -8023,7 +8053,7 @@
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
- name, applicationHandle, flags);
+ name, applicationHandle, flags, null /* region */);
clientChannel.transferTo(outInputChannel);
clientChannel.dispose();
@@ -8035,7 +8065,7 @@
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
int displayId, SurfaceControl surface, String name,
- InputApplicationHandle applicationHandle, int flags) {
+ InputApplicationHandle applicationHandle, int flags, Region region) {
InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.name = name;
@@ -8044,7 +8074,7 @@
| LayoutParams.FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = 0;
- h.dispatchingTimeoutNanos = -1;
+ h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
h.canReceiveKeys = false;
h.hasFocus = false;
h.hasWallpaper = false;
@@ -8055,7 +8085,13 @@
h.inputFeatures = 0;
- h.replaceTouchableRegionWithCrop(null);
+ if (region == null) {
+ h.replaceTouchableRegionWithCrop(null);
+ } else {
+ h.touchableRegion.set(region);
+ h.replaceTouchableRegionWithCrop = false;
+ h.setTouchableRegionCrop(surface);
+ }
SurfaceControl.Transaction t = mTransactionFactory.get();
t.setInputWindowInfo(surface, h);
@@ -8069,7 +8105,7 @@
* is undefined.
*/
void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags) {
+ int flags, Region region) {
final InputApplicationHandle applicationHandle;
final String name;
final EmbeddedWindowController.EmbeddedWindow win;
@@ -8084,7 +8120,7 @@
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
- applicationHandle, flags);
+ applicationHandle, flags, region);
}
/** Return whether layer tracing is enabled */
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0e83bee..c570cf1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -846,6 +846,23 @@
}
}
+ private boolean shouldConsumeMainWindowSizeTransaction() {
+ // We only consume the transaction when the client is calling relayout
+ // because this is the only time we know the frameNumber will be valid
+ // due to the client renderer being paused. Put otherwise, only when
+ // mInRelayout is true can we guarantee the next frame will contain
+ // the most recent configuration.
+ if (!mWin.mInRelayout) return false;
+ // Since we can only do this for one window, we focus on the main application window
+ if (mAttrType != TYPE_BASE_APPLICATION) return false;
+ final Task task = mWin.getTask();
+ if (task == null) return false;
+ if (task.getMainWindowSizeChangeTransaction() == null) return false;
+ // Likewise we only focus on the task root, since we can only use one window
+ if (!mWin.mActivityRecord.isRootOfTask()) return false;
+ return true;
+ }
+
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
if (mSurfaceController == null) {
return;
@@ -886,8 +903,9 @@
clipRect = mTmpClipRect;
}
- if (w.mInRelayout && (mAttrType == TYPE_BASE_APPLICATION) && (task != null)
- && (task.getMainWindowSizeChangeTransaction() != null)) {
+ if (shouldConsumeMainWindowSizeTransaction()) {
+ task.getSurfaceControl().deferTransactionUntil(mWin.getClientViewRootSurface(),
+ mWin.getFrameNumber());
mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
mWin.getFrameNumber());
SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9bc5d34..2013945 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -237,27 +237,28 @@
/* --- InputDispatcherPolicyInterface implementation --- */
virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
- uint32_t policyFlags);
+ uint32_t policyFlags) override;
virtual void notifyConfigurationChanged(nsecs_t when);
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token,
- const std::string& reason);
+ virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) override;
virtual void notifyInputChannelBroken(const sp<IBinder>& token);
- virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken);
- virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
- virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken,
+ const sp<IBinder>& newToken) override;
+ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
+ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
+ uint32_t& policyFlags) override;
virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
- uint32_t& policyFlags);
- virtual nsecs_t interceptKeyBeforeDispatching(
- const sp<IBinder>& token,
- const KeyEvent* keyEvent, uint32_t policyFlags);
- virtual bool dispatchUnhandledKey(const sp<IBinder>& token,
- const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent);
- virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
- virtual bool checkInjectEventsPermissionNonReentrant(
- int32_t injectorPid, int32_t injectorUid);
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken);
+ uint32_t& policyFlags) override;
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
+ const KeyEvent* keyEvent,
+ uint32_t policyFlags) override;
+ virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
+ uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
+ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) override;
+ virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
+ int32_t injectorUid) override;
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -692,9 +693,8 @@
return handle->getInputApplicationHandleObjLocalRef(env);
}
-
-nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) {
+nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -1453,9 +1453,13 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
- & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
- uint32_t(policyFlags));
+ const int32_t result =
+ im->getInputManager()->getDispatcher()->injectInputEvent(&keyEvent, injectorPid,
+ injectorUid, syncMode,
+ std::chrono::milliseconds(
+ timeoutMillis),
+ uint32_t(policyFlags));
+ return static_cast<jint>(result);
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
if (!motionEvent) {
@@ -1463,9 +1467,13 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
- motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
- uint32_t(policyFlags));
+ const int32_t result =
+ (jint)im->getInputManager()
+ ->getDispatcher()
+ ->injectInputEvent(motionEvent, injectorPid, injectorUid, syncMode,
+ std::chrono::milliseconds(timeoutMillis),
+ uint32_t(policyFlags));
+ return static_cast<jint>(result);
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp
index e4f5464..df054b0 100644
--- a/services/coverage/Android.bp
+++ b/services/coverage/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.coverage",
+ defaults: ["services_defaults"],
srcs: [":services.coverage-sources"],
libs: ["jacocoagent"],
}
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 2f6592b..7a80fb1 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.devicepolicy",
+ defaults: ["services_defaults"],
srcs: [":services.devicepolicy-sources"],
libs: [
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a74706b..966694a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -22,6 +22,7 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
@@ -409,6 +410,12 @@
private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION =
"com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
+ /** Broadcast action invoked when the user taps a notification to turn the profile on. */
+ @VisibleForTesting
+ static final String ACTION_TURN_PROFILE_ON_NOTIFICATION =
+ "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION";
+
+ /** Broadcast action for tracking managed profile maximum time off. */
@VisibleForTesting
static final String ACTION_PROFILE_OFF_DEADLINE =
"com.android.server.ACTION_PROFILE_OFF_DEADLINE";
@@ -951,7 +958,10 @@
}
if (isManagedProfile(userHandle)) {
Slog.d(LOG_TAG, "Managed profile became unlocked");
- updatePersonalAppsSuspension(userHandle, true /* unlocked */);
+ if (updatePersonalAppsSuspension(userHandle, true /* unlocked */)
+ == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT) {
+ triggerPolicyComplianceCheck(userHandle);
+ }
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
handlePackagesChanged(null /* check all admins */, userHandle);
@@ -982,6 +992,9 @@
} else {
Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile");
}
+ } else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) {
+ Slog.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
+ mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle));
}
}
@@ -2568,6 +2581,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
+ filter.addAction(ACTION_TURN_PROFILE_ON_NOTIFICATION);
filter.addAction(ACTION_PROFILE_OFF_DEADLINE);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -4553,9 +4567,11 @@
}
if (isProfileOwner(adminReceiver, userHandle)) {
if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
+ UserHandle parentUserHandle = UserHandle.of(getProfileParentId(userHandle));
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
- false,
- UserHandle.of(getProfileParentId(userHandle)));
+ false, parentUserHandle);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+ false, parentUserHandle);
}
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver,
userHandle, /* parent */ false);
@@ -5904,12 +5920,22 @@
}
final int userHandle = mInjector.userHandleGetCallingUserId();
+ boolean changed = false;
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
if (ap.strongAuthUnlockTimeout != timeoutMs) {
ap.strongAuthUnlockTimeout = timeoutMs;
saveSettingsLocked(userHandle);
+ changed = true;
+ }
+ }
+ if (changed) {
+ mLockSettingsInternal.refreshStrongAuthTimeout(userHandle);
+ // Refreshes the parent if profile has unified challenge, since the timeout would
+ // also affect the parent user in this case.
+ if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) {
+ mLockSettingsInternal.refreshStrongAuthTimeout(getProfileParentId(userHandle));
}
}
}
@@ -7189,6 +7215,8 @@
mUserManager.setUserRestriction(
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
UserHandle.SYSTEM);
+ mUserManager.setUserRestriction(
+ UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM);
// Device-wide policies set by the profile owner need to be cleaned up here.
mLockPatternUtils.setDeviceOwnerInfo(null);
@@ -13801,6 +13829,8 @@
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
parentUser);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+ parentUser);
});
// markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
@@ -15940,14 +15970,29 @@
.write();
}
+ /** Starts an activity to check policy compliance in the DPC. */
+ private void triggerPolicyComplianceCheck(int profileUserId) {
+ final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
+ synchronized (getLockObject()) {
+ final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId);
+ if (profileOwner == null) {
+ Slog.wtf(LOG_TAG, "Profile owner not found for compliance check");
+ return;
+ }
+ intent.setPackage(profileOwner.info.getPackageName());
+ }
+ mContext.startActivityAsUser(intent, UserHandle.of(profileUserId));
+ }
+
/**
* Checks whether personal apps should be suspended according to the policy and applies the
* change if needed.
*
* @param unlocked whether the profile is currently running unlocked.
*/
- private void updatePersonalAppsSuspension(int profileUserId, boolean unlocked) {
- final boolean suspended;
+ private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension(
+ int profileUserId, boolean unlocked) {
+ final boolean suspendedExplicitly;
final int deadlineState;
final String poPackage;
synchronized (getLockObject()) {
@@ -15955,26 +16000,28 @@
if (profileOwner != null) {
deadlineState =
updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked);
- suspended = profileOwner.mSuspendPersonalApps
- || deadlineState == PROFILE_OFF_DEADLINE_REACHED;
+ suspendedExplicitly = profileOwner.mSuspendPersonalApps;
poPackage = profileOwner.info.getPackageName();
} else {
poPackage = null;
- suspended = false;
+ suspendedExplicitly = false;
deadlineState = PROFILE_OFF_DEADLINE_DEFAULT;
}
}
- Slog.d(LOG_TAG, String.format("Personal apps suspended: %b, deadline state: %d",
- suspended, deadlineState));
+ Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d",
+ suspendedExplicitly, deadlineState));
if (poPackage != null) {
final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState;
updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState);
}
+ final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED;
final int parentUserId = getProfileParentId(profileUserId);
- suspendPersonalAppsInternal(parentUserId, suspended);
+ suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout);
+
+ return makeSuspensionReasons(suspendedExplicitly, suspendedByTimeout);
}
/**
@@ -16034,8 +16081,10 @@
}
final AlarmManager am = mInjector.getAlarmManager();
+ final Intent intent = new Intent(ACTION_PROFILE_OFF_DEADLINE);
+ intent.setPackage(mContext.getPackageName());
final PendingIntent pi = mInjector.pendingIntentGetBroadcast(
- mContext, REQUEST_PROFILE_OFF_DEADLINE, new Intent(ACTION_PROFILE_OFF_DEADLINE),
+ mContext, REQUEST_PROFILE_OFF_DEADLINE, intent,
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
if (alarmTime == 0) {
@@ -16084,28 +16133,35 @@
return;
}
- final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
- intent.setPackage(profileOwnerPackage);
+ final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
- final PendingIntent pendingIntent = mInjector.pendingIntentGetActivityAsUser(mContext,
- 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT,
- null /* options */, UserHandle.of(profileUserId));
+ final PendingIntent pendingIntent = mInjector.pendingIntentGetBroadcast(mContext,
+ 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- // TODO(b/149075510): Only the first of the notifications should be dismissible.
+ final String buttonText =
+ mContext.getString(R.string.personal_apps_suspended_turn_profile_on);
+ final Notification.Action turnProfileOnButton =
+ new Notification.Action.Builder(null /* icon */, buttonText, pendingIntent).build();
+
final String text = mContext.getString(
notificationState == PROFILE_OFF_DEADLINE_WARNING
? R.string.personal_apps_suspension_tomorrow_text
: R.string.personal_apps_suspension_text);
+ final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED;
final Notification notification =
new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(android.R.drawable.stat_sys_warning)
- .setOngoing(true)
+ .setOngoing(ongoing)
+ .setAutoCancel(false)
.setContentTitle(mContext.getString(
R.string.personal_apps_suspension_title))
.setContentText(text)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setContentIntent(pendingIntent)
+ .addAction(turnProfileOnButton)
.build();
mInjector.getNotificationManager().notify(
SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED, notification);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 992a4ef..d412a19 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -266,6 +266,7 @@
mIncFs(sm.getIncFs()),
mAppOpsManager(sm.getAppOpsManager()),
mJni(sm.getJni()),
+ mLooper(sm.getLooper()),
mIncrementalDir(rootDir) {
if (!mVold) {
LOG(FATAL) << "Vold service is unavailable";
@@ -276,12 +277,22 @@
if (!mAppOpsManager) {
LOG(FATAL) << "AppOpsManager is unavailable";
}
+ if (!mJni) {
+ LOG(FATAL) << "JNI is unavailable";
+ }
+ if (!mLooper) {
+ LOG(FATAL) << "Looper is unavailable";
+ }
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
mJni->initializeForCurrentThread();
runJobProcessing();
});
+ mCmdLooperThread = std::thread([this]() {
+ mJni->initializeForCurrentThread();
+ runCmdLooper();
+ });
const auto mountedRootNames = adoptMountedInstances();
mountExistingImages(mountedRootNames);
@@ -294,6 +305,7 @@
}
mJobCondition.notify_all();
mJobProcessor.join();
+ mCmdLooperThread.join();
}
static const char* toString(IncrementalService::BindKind kind) {
@@ -1315,6 +1327,13 @@
return true;
}
+void IncrementalService::runCmdLooper() {
+ constexpr auto kTimeoutMsecs = 1000;
+ while (mRunning.load(std::memory_order_relaxed)) {
+ mLooper->pollAll(kTimeoutMsecs);
+ }
+}
+
IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
IncFsMount& ifs, DataLoaderParamsParcel&& params,
const DataLoaderStatusListener* externalListener) {
@@ -1337,8 +1356,16 @@
fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
- ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params),
- std::move(fsControlParcel), externalListener);
+ incfs::UniqueControl healthControl = mIncFs->openMount(ifs.root.c_str());
+ if (healthControl.pendingReads() < 0) {
+ LOG(ERROR) << "Failed to open health control for: " << ifs.root << "("
+ << healthControl.cmd() << ":" << healthControl.pendingReads() << ":"
+ << healthControl.logs() << ")";
+ }
+
+ ifs.dataLoaderStub =
+ new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel),
+ std::move(healthControl), externalListener);
}
template <class Duration>
@@ -1658,21 +1685,37 @@
IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
DataLoaderParamsParcel&& params,
FileSystemControlParcel&& control,
+ incfs::UniqueControl&& healthControl,
const DataLoaderStatusListener* externalListener)
: mService(service),
mId(id),
mParams(std::move(params)),
mControl(std::move(control)),
+ mHealthControl(std::move(healthControl)),
mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {
+ addToCmdLooperLocked();
}
-IncrementalService::DataLoaderStub::~DataLoaderStub() = default;
+IncrementalService::DataLoaderStub::~DataLoaderStub() {
+ if (mId != kInvalidStorageId) {
+ cleanupResources();
+ }
+}
void IncrementalService::DataLoaderStub::cleanupResources() {
requestDestroy();
+
+ auto now = Clock::now();
+ std::unique_lock lock(mMutex);
+
+ removeFromCmdLooperLocked();
+
mParams = {};
mControl = {};
- waitForStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED, std::chrono::seconds(60));
+ mHealthControl = {};
+ mStatusCondition.wait_until(lock, now + 60s, [this] {
+ return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
+ });
mListener = {};
mId = kInvalidStorageId;
}
@@ -1704,28 +1747,19 @@
}
bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
- int oldStatus, curStatus;
{
- std::unique_lock lock(mStatusMutex);
- oldStatus = mTargetStatus;
- curStatus = mCurrentStatus;
+ std::unique_lock lock(mMutex);
setTargetStatusLocked(newStatus);
}
- LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
- << newStatus << " (current " << curStatus << ")";
return fsmStep();
}
void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
+ auto oldStatus = mTargetStatus;
mTargetStatus = status;
mTargetStatusTs = Clock::now();
-}
-
-bool IncrementalService::DataLoaderStub::waitForStatus(int status, Clock::duration duration) {
- auto now = Clock::now();
- std::unique_lock lock(mStatusMutex);
- return mStatusCondition.wait_until(lock, now + duration,
- [this, status] { return mCurrentStatus == status; });
+ LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
+ << status << " (current " << mCurrentStatus << ")";
}
bool IncrementalService::DataLoaderStub::bind() {
@@ -1776,7 +1810,7 @@
int currentStatus;
int targetStatus;
{
- std::unique_lock lock(mStatusMutex);
+ std::unique_lock lock(mMutex);
currentStatus = mCurrentStatus;
targetStatus = mTargetStatus;
}
@@ -1828,8 +1862,9 @@
}
int targetStatus, oldStatus;
+ DataLoaderStatusListener listener;
{
- std::unique_lock lock(mStatusMutex);
+ std::unique_lock lock(mMutex);
if (mCurrentStatus == newStatus) {
return binder::Status::ok();
}
@@ -1838,6 +1873,8 @@
mCurrentStatus = newStatus;
targetStatus = mTargetStatus;
+ listener = mListener;
+
if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) {
// For unavailable, reset target status.
setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE);
@@ -1847,8 +1884,8 @@
LOG(DEBUG) << "Current status update for DataLoader " << mId << ": " << oldStatus << " -> "
<< newStatus << " (target " << targetStatus << ")";
- if (mListener) {
- mListener->onStatusChanged(mountId, newStatus);
+ if (listener) {
+ listener->onStatusChanged(mountId, newStatus);
}
fsmStep();
@@ -1858,12 +1895,75 @@
return binder::Status::ok();
}
+void IncrementalService::DataLoaderStub::addToCmdLooperLocked() {
+ const auto pendingReadsFd = mHealthControl.pendingReads();
+ if (pendingReadsFd < 0) {
+ return;
+ }
+
+ mService.mLooper->addFd(
+ pendingReadsFd, android::Looper::POLL_CALLBACK, android::Looper::EVENT_INPUT,
+ [](int, int, void* data) -> int {
+ auto&& self = (DataLoaderStub*)data;
+ return self->onCmdLooperEvent();
+ },
+ this);
+ mService.mLooper->wake();
+}
+
+void IncrementalService::DataLoaderStub::removeFromCmdLooperLocked() {
+ const auto pendingReadsFd = mHealthControl.pendingReads();
+ if (pendingReadsFd < 0) {
+ return;
+ }
+
+ mService.mLooper->removeFd(pendingReadsFd);
+ mService.mLooper->wake();
+}
+
+int IncrementalService::DataLoaderStub::onCmdLooperEvent() {
+ if (!mService.mRunning.load(std::memory_order_relaxed)) {
+ return 0;
+ }
+
+ bool pendingReadsOccur = false;
+
+ {
+ std::unique_lock lock(mMutex);
+ const auto now = Clock::now();
+ if (now < mEarliestMissingPageTs) {
+ // Transition: duration::max -> now.
+ mEarliestMissingPageTs = now;
+ pendingReadsOccur = true;
+ }
+ }
+
+ if (pendingReadsOccur) {
+ LOG(INFO) << "Pending reads occur for, requesting start for: " << mId;
+ requestStart();
+ }
+
+ {
+ // Drop pending reads.
+ static constexpr auto kMaxDropIterations = 3;
+ std::unique_lock lock(mMutex);
+ for (int i = 0; i < kMaxDropIterations; ++i) {
+ if (IncFs_DropPendingReads(mHealthControl) <= 0) {
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " dataLoader: {\n");
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
dprintf(fd, " targetStatus: %d\n", mTargetStatus);
dprintf(fd, " targetStatusTs: %lldmcs\n",
(long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
+ dprintf(fd, " earliestMissingPageTs: %lldmcs\n",
+ (long long)(elapsedMcs(mEarliestMissingPageTs, Clock::now())));
const auto& params = mParams;
dprintf(fd, " dataLoaderParams: {\n");
dprintf(fd, " type: %s\n", toString(params.type).c_str());
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index d5c612d..640ca53 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -18,6 +18,7 @@
#include <android/content/pm/BnDataLoaderStatusListener.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
+#include <android/content/pm/FileSystemControlParcel.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/incremental/BnIncrementalServiceConnector.h>
#include <binder/IAppOpsCallback.h>
@@ -160,6 +161,7 @@
DataLoaderStub(IncrementalService& service, MountId id,
content::pm::DataLoaderParamsParcel&& params,
content::pm::FileSystemControlParcel&& control,
+ incfs::UniqueControl&& healthControl,
const DataLoaderStatusListener* externalListener);
~DataLoaderStub();
// Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
@@ -178,6 +180,10 @@
private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
+ void addToCmdLooperLocked();
+ void removeFromCmdLooperLocked();
+ int onCmdLooperEvent();
+
bool isValid() const { return mId != kInvalidStorageId; }
sp<content::pm::IDataLoader> getDataLoader();
@@ -188,21 +194,24 @@
bool setTargetStatus(int status);
void setTargetStatusLocked(int status);
- bool waitForStatus(int status, Clock::duration duration);
bool fsmStep();
IncrementalService& mService;
+
+ std::mutex mMutex;
MountId mId = kInvalidStorageId;
content::pm::DataLoaderParamsParcel mParams;
content::pm::FileSystemControlParcel mControl;
+ incfs::UniqueControl mHealthControl;
DataLoaderStatusListener mListener;
- std::mutex mStatusMutex;
std::condition_variable mStatusCondition;
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
TimePoint mTargetStatusTs = {};
+
+ TimePoint mEarliestMissingPageTs{Clock::duration::max()};
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
@@ -300,12 +309,15 @@
const incfs::FileId& libFileId, std::string_view targetLibPath,
Clock::time_point scheduledTs);
+ void runCmdLooper();
+
private:
const std::unique_ptr<VoldServiceWrapper> mVold;
const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
const std::unique_ptr<IncFsWrapper> mIncFs;
const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager;
const std::unique_ptr<JniWrapper> mJni;
+ const std::unique_ptr<LooperWrapper> mLooper;
const std::string mIncrementalDir;
mutable std::mutex mLock;
@@ -319,13 +331,16 @@
std::atomic_bool mSystemReady = false;
StorageId mNextId = 0;
+ std::atomic_bool mRunning{true};
+
using Job = std::function<void()>;
std::unordered_map<MountId, std::vector<Job>> mJobQueue;
MountId mPendingJobsMount = kInvalidStorageId;
std::condition_variable mJobCondition;
std::mutex mJobMutex;
std::thread mJobProcessor;
- bool mRunning = true;
+
+ std::thread mCmdLooperThread;
};
} // namespace android::incremental
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 85f7441..08fb486 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -113,6 +113,23 @@
JavaVM* const mJvm;
};
+class RealLooperWrapper final : public LooperWrapper {
+public:
+ int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
+ void* data) final {
+ return mLooper.addFd(fd, ident, events, callback, data);
+ }
+ int removeFd(int fd) final { return mLooper.removeFd(fd); }
+ void wake() final { return mLooper.wake(); }
+ int pollAll(int timeoutMillis) final { return mLooper.pollAll(timeoutMillis); }
+
+private:
+ struct Looper : public android::Looper {
+ Looper() : android::Looper(/*allowNonCallbacks=*/false) {}
+ ~Looper() {}
+ } mLooper;
+};
+
class RealIncFs : public IncFsWrapper {
public:
RealIncFs() = default;
@@ -203,6 +220,10 @@
return std::make_unique<RealJniWrapper>(mJvm);
}
+std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() {
+ return std::make_unique<RealLooperWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 3792830..abbf2f4 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -26,6 +26,7 @@
#include <binder/Status.h>
#include <incfs.h>
#include <jni.h>
+#include <utils/Looper.h>
#include <memory>
#include <span>
@@ -106,6 +107,16 @@
virtual void initializeForCurrentThread() const = 0;
};
+class LooperWrapper {
+public:
+ virtual ~LooperWrapper() = default;
+ virtual int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
+ void* data) = 0;
+ virtual int removeFd(int fd) = 0;
+ virtual void wake() = 0;
+ virtual int pollAll(int timeoutMillis) = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -114,6 +125,7 @@
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0;
virtual std::unique_ptr<JniWrapper> getJni() = 0;
+ virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
};
// --- Real stuff ---
@@ -127,6 +139,7 @@
std::unique_ptr<IncFsWrapper> getIncFs() final;
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final;
std::unique_ptr<JniWrapper> getJni() final;
+ std::unique_ptr<LooperWrapper> getLooper() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 2205bfe..325218d 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -242,6 +242,9 @@
void setDataLoaderStatusDestroyed() {
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
}
+ void setDataLoaderStatusUnavailable() {
+ mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE);
+ }
binder::Status unbindFromDataLoaderOk(int32_t id) {
if (mDataLoader) {
if (auto status = mDataLoader->destroy(id); !status.isOk()) {
@@ -286,6 +289,14 @@
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+ void openMountSuccess() {
+ ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
+ }
+
+ static constexpr auto kPendingReadsFd = 42;
+ Control openMountForHealth(std::string_view) {
+ return UniqueControl(IncFs_CreateControl(-1, kPendingReadsFd, -1));
+ }
RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) {
metadata::Mount m;
@@ -346,7 +357,42 @@
public:
MOCK_CONST_METHOD0(initializeForCurrentThread, void());
- MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); }
+ MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(2); }
+};
+
+class MockLooperWrapper : public LooperWrapper {
+public:
+ MOCK_METHOD5(addFd, int(int, int, int, android::Looper_callbackFunc, void*));
+ MOCK_METHOD1(removeFd, int(int));
+ MOCK_METHOD0(wake, void());
+ MOCK_METHOD1(pollAll, int(int));
+
+ MockLooperWrapper() {
+ ON_CALL(*this, addFd(_, _, _, _, _))
+ .WillByDefault(Invoke(this, &MockLooperWrapper::storeCallback));
+ ON_CALL(*this, removeFd(_)).WillByDefault(Invoke(this, &MockLooperWrapper::clearCallback));
+ ON_CALL(*this, pollAll(_)).WillByDefault(Invoke(this, &MockLooperWrapper::sleepFor));
+ }
+
+ int storeCallback(int, int, int, android::Looper_callbackFunc callback, void* data) {
+ mCallback = callback;
+ mCallbackData = data;
+ return 0;
+ }
+
+ int clearCallback(int) {
+ mCallback = nullptr;
+ mCallbackData = nullptr;
+ return 0;
+ }
+
+ int sleepFor(int timeoutMillis) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(timeoutMillis));
+ return 0;
+ }
+
+ android::Looper_callbackFunc mCallback = nullptr;
+ void* mCallbackData = nullptr;
};
class MockServiceManager : public ServiceManagerWrapper {
@@ -355,12 +401,14 @@
std::unique_ptr<MockDataLoaderManager> dataLoaderManager,
std::unique_ptr<MockIncFs> incfs,
std::unique_ptr<MockAppOpsManager> appOpsManager,
- std::unique_ptr<MockJniWrapper> jni)
+ std::unique_ptr<MockJniWrapper> jni,
+ std::unique_ptr<MockLooperWrapper> looper)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
mAppOpsManager(std::move(appOpsManager)),
- mJni(std::move(jni)) {}
+ mJni(std::move(jni)),
+ mLooper(std::move(looper)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
@@ -368,6 +416,7 @@
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
+ std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -375,6 +424,7 @@
std::unique_ptr<MockIncFs> mIncFs;
std::unique_ptr<MockAppOpsManager> mAppOpsManager;
std::unique_ptr<MockJniWrapper> mJni;
+ std::unique_ptr<MockLooperWrapper> mLooper;
};
// --- IncrementalServiceTest ---
@@ -394,13 +444,16 @@
mAppOpsManager = appOps.get();
auto jni = std::make_unique<NiceMock<MockJniWrapper>>();
mJni = jni.get();
+ auto looper = std::make_unique<NiceMock<MockLooperWrapper>>();
+ mLooper = looper.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
dataloaderManager),
std::move(incFs),
std::move(appOps),
- std::move(jni)),
+ std::move(jni),
+ std::move(looper)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
@@ -430,12 +483,13 @@
}
protected:
- NiceMock<MockVoldService>* mVold;
- NiceMock<MockIncFs>* mIncFs;
- NiceMock<MockDataLoaderManager>* mDataLoaderManager;
- NiceMock<MockAppOpsManager>* mAppOpsManager;
- NiceMock<MockJniWrapper>* mJni;
- NiceMock<MockDataLoader>* mDataLoader;
+ NiceMock<MockVoldService>* mVold = nullptr;
+ NiceMock<MockIncFs>* mIncFs = nullptr;
+ NiceMock<MockDataLoaderManager>* mDataLoaderManager = nullptr;
+ NiceMock<MockAppOpsManager>* mAppOpsManager = nullptr;
+ NiceMock<MockJniWrapper>* mJni = nullptr;
+ NiceMock<MockLooperWrapper>* mLooper = nullptr;
+ NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
DataLoaderParamsParcel mDataLoaderParcel;
@@ -593,6 +647,54 @@
mDataLoaderManager->setDataLoaderStatusCreated();
}
+TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoader->initializeCreateOkNoStatus();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+}
+
+TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mIncFs->openMountSuccess();
+ mVold->bindMountSuccess();
+ mDataLoader->initializeCreateOkNoStatus();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(0);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ mDataLoaderManager->setDataLoaderStatusUnavailable();
+ ASSERT_NE(nullptr, mLooper->mCallback);
+ ASSERT_NE(nullptr, mLooper->mCallbackData);
+ mLooper->mCallback(-1, -1, mLooper->mCallbackData);
+}
+
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0fc333f..fa3f330 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1891,6 +1891,10 @@
|| mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
t.traceBegin("StartTvInputManager");
mSystemServiceManager.startService(TvInputManagerService.class);
+ t.traceEnd();
+ }
+
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_TUNER)) {
t.traceBegin("StartTunerResourceManager");
mSystemServiceManager.startService(TunerResourceManagerService.class);
t.traceEnd();
diff --git a/services/midi/Android.bp b/services/midi/Android.bp
index 20e0083..6bce5b5 100644
--- a/services/midi/Android.bp
+++ b/services/midi/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.midi",
+ defaults: ["services_defaults"],
srcs: [":services.midi-sources"],
libs: ["services.core"],
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index bb5409b..afea1a0 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -7,13 +7,13 @@
java_library_static {
name: "services.net",
+ defaults: ["services_defaults"],
srcs: [
":net-module-utils-srcs",
":services.net-sources",
],
static_libs: [
- "dnsresolver_aidl_interface-V4-java",
- "netd_aidl_interface-V3-java",
+ "netd_aidl_interfaces-platform-java",
"netlink-client",
"networkstack-client",
"net-utils-services-common",
@@ -44,7 +44,8 @@
"framework-wifi-util-lib",
],
static_libs: [
- "dnsresolver_aidl_interface-V2-java",
+ // All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
+ // classes generated by netd_aidl_interfaces-platform-java above.
"netd_aidl_interface-V3-java",
"netlink-client",
"networkstack-client",
diff --git a/services/people/Android.bp b/services/people/Android.bp
index d64097a..c863f1f 100644
--- a/services/people/Android.bp
+++ b/services/people/Android.bp
@@ -1,5 +1,6 @@
java_library_static {
name: "services.people",
+ defaults: ["services_defaults"],
srcs: ["java/**/*.java"],
libs: ["services.core"],
}
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 27fa36b..dc3fa2a 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -62,8 +62,6 @@
private static final int FLAG_DEMOTED = 1 << 6;
- private static final int FLAG_NOTIFICATION_SETTING_CHANGED = 1 << 7;
-
@IntDef(flag = true, prefix = {"FLAG_"}, value = {
FLAG_IMPORTANT,
FLAG_NOTIFICATION_SILENCED,
@@ -72,7 +70,6 @@
FLAG_PERSON_BOT,
FLAG_CONTACT_STARRED,
FLAG_DEMOTED,
- FLAG_NOTIFICATION_SETTING_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
private @interface ConversationFlags {
@@ -188,11 +185,6 @@
return hasConversationFlags(FLAG_CONTACT_STARRED);
}
- /** Whether the conversation's notification setting has ever been changed by the user. */
- boolean isNotificationSettingChanged() {
- return hasConversationFlags(FLAG_NOTIFICATION_SETTING_CHANGED);
- }
-
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -499,10 +491,6 @@
return setConversationFlag(FLAG_CONTACT_STARRED, value);
}
- Builder setNotificationSettingChanged(boolean value) {
- return setConversationFlag(FLAG_NOTIFICATION_SETTING_CHANGED, value);
- }
-
private Builder setConversationFlag(@ConversationFlags int flags, boolean value) {
if (value) {
return addConversationFlags(flags);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 8e1141d..107c41a 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -16,8 +16,6 @@
package com.android.server.people.data;
-import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -60,9 +58,11 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
import com.android.internal.content.PackageMonitor;
@@ -106,8 +106,7 @@
private final SparseArray<BroadcastReceiver> mBroadcastReceivers = new SparseArray<>();
private final SparseArray<ContentObserver> mContactsContentObservers = new SparseArray<>();
private final SparseArray<ScheduledFuture<?>> mUsageStatsQueryFutures = new SparseArray<>();
- private final SparseArray<NotificationListenerService> mNotificationListeners =
- new SparseArray<>();
+ private final SparseArray<NotificationListener> mNotificationListeners = new SparseArray<>();
private final SparseArray<PackageMonitor> mPackageMonitors = new SparseArray<>();
private ContentObserver mCallLogContentObserver;
private ContentObserver mMmsSmsContentObserver;
@@ -230,6 +229,10 @@
return;
}
String shortcutId = appTarget.getShortcutInfo().getId();
+ // Skip storing chooserTargets sharing events
+ if (ChooserActivity.CHOOSER_TARGET.equals(shortcutId)) {
+ return;
+ }
if (packageData.getConversationStore().getConversation(shortcutId) == null) {
addOrUpdateConversationInfo(appTarget.getShortcutInfo());
}
@@ -272,6 +275,7 @@
}
pruneUninstalledPackageData(userData);
+ final NotificationListener notificationListener = mNotificationListeners.get(userId);
userData.forAllPackages(packageData -> {
if (signal.isCanceled()) {
return;
@@ -284,6 +288,20 @@
packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_SMS);
}
packageData.pruneOrphanEvents();
+ if (notificationListener != null) {
+ String packageName = packageData.getPackageName();
+ packageData.forAllConversations(conversationInfo -> {
+ if (conversationInfo.isShortcutCached()
+ && conversationInfo.getNotificationChannelId() == null
+ && !notificationListener.hasActiveNotifications(
+ packageName, conversationInfo.getShortcutId())) {
+ mShortcutServiceInternal.uncacheShortcuts(userId,
+ mContext.getPackageName(), packageName,
+ Collections.singletonList(conversationInfo.getShortcutId()),
+ userId);
+ }
+ });
+ }
});
}
@@ -337,7 +355,7 @@
Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
contactsContentObserver, userId);
- NotificationListener notificationListener = new NotificationListener();
+ NotificationListener notificationListener = new NotificationListener(userId);
mNotificationListeners.put(userId, notificationListener);
try {
notificationListener.registerAsSystemService(mContext,
@@ -753,14 +771,27 @@
/** Listener for the notifications and their settings changes. */
private class NotificationListener extends NotificationListenerService {
- // Conversation shortcut ID -> Number of active notifications
- private final Map<String, Integer> mActiveNotifCounts = new ArrayMap<>();
+ private final int mUserId;
+
+ // Conversation package name + shortcut ID -> Number of active notifications
+ @GuardedBy("this")
+ private final Map<Pair<String, String>, Integer> mActiveNotifCounts = new ArrayMap<>();
+
+ private NotificationListener(int userId) {
+ mUserId = userId;
+ }
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
+ if (sbn.getUser().getIdentifier() != mUserId) {
+ return;
+ }
String shortcutId = sbn.getNotification().getShortcutId();
PackageData packageData = getPackageIfConversationExists(sbn, conversationInfo -> {
- mActiveNotifCounts.merge(shortcutId, 1, Integer::sum);
+ synchronized (this) {
+ mActiveNotifCounts.merge(
+ Pair.create(sbn.getPackageName(), shortcutId), 1, Integer::sum);
+ }
});
if (packageData != null) {
@@ -771,26 +802,32 @@
}
@Override
- public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
- int reason) {
+ public synchronized void onNotificationRemoved(StatusBarNotification sbn,
+ RankingMap rankingMap, int reason) {
+ if (sbn.getUser().getIdentifier() != mUserId) {
+ return;
+ }
String shortcutId = sbn.getNotification().getShortcutId();
PackageData packageData = getPackageIfConversationExists(sbn, conversationInfo -> {
- int count = mActiveNotifCounts.getOrDefault(shortcutId, 0) - 1;
- if (count <= 0) {
- mActiveNotifCounts.remove(sbn.getNotification().getShortcutId());
- // The shortcut was cached by Notification Manager synchronously when the
- // associated notification was posted. Uncache it here when all the associated
- // notifications are removed.
- if (conversationInfo.isShortcutCached()
- && !conversationInfo.isNotificationSettingChanged()) {
- int userId = sbn.getUser().getIdentifier();
- mShortcutServiceInternal.uncacheShortcuts(userId,
- mContext.getPackageName(), sbn.getPackageName(),
- Collections.singletonList(conversationInfo.getShortcutId()),
- userId);
+ Pair<String, String> conversationKey =
+ Pair.create(sbn.getPackageName(), shortcutId);
+ synchronized (this) {
+ int count = mActiveNotifCounts.getOrDefault(conversationKey, 0) - 1;
+ if (count <= 0) {
+ mActiveNotifCounts.remove(conversationKey);
+ // The shortcut was cached by Notification Manager synchronously when the
+ // associated notification was posted. Uncache it here when all the
+ // associated notifications are removed.
+ if (conversationInfo.isShortcutCached()
+ && conversationInfo.getNotificationChannelId() == null) {
+ mShortcutServiceInternal.uncacheShortcuts(mUserId,
+ mContext.getPackageName(), sbn.getPackageName(),
+ Collections.singletonList(conversationInfo.getShortcutId()),
+ mUserId);
+ }
+ } else {
+ mActiveNotifCounts.put(conversationKey, count);
}
- } else {
- mActiveNotifCounts.put(shortcutId, count);
}
});
@@ -806,6 +843,9 @@
@Override
public void onNotificationChannelModified(String pkg, UserHandle user,
NotificationChannel channel, int modificationType) {
+ if (user.getIdentifier() != mUserId) {
+ return;
+ }
PackageData packageData = getPackage(pkg, user.getIdentifier());
String shortcutId = channel.getConversationId();
if (packageData == null || shortcutId == null) {
@@ -816,16 +856,7 @@
if (conversationInfo == null) {
return;
}
- boolean isNotificationSettingChanged =
- conversationInfo.isImportant() != channel.isImportantConversation()
- || conversationInfo.isDemoted() != channel.isDemoted()
- || channel.hasUserSetImportance()
- || (channel.getUserLockedFields() & USER_LOCKED_ALLOW_BUBBLE) != 0;
ConversationInfo.Builder builder = new ConversationInfo.Builder(conversationInfo);
- if (modificationType == NOTIFICATION_CHANNEL_OR_GROUP_UPDATED
- && isNotificationSettingChanged) {
- builder.setNotificationSettingChanged(true);
- }
switch (modificationType) {
case NOTIFICATION_CHANNEL_OR_GROUP_ADDED:
case NOTIFICATION_CHANNEL_OR_GROUP_UPDATED:
@@ -848,6 +879,28 @@
}
conversationStore.addOrUpdate(builder.build());
}
+
+ synchronized void cleanupCachedShortcuts() {
+ for (Pair<String, String> conversationKey : mActiveNotifCounts.keySet()) {
+ String packageName = conversationKey.first;
+ String shortcutId = conversationKey.second;
+ PackageData packageData = getPackage(packageName, mUserId);
+ ConversationInfo conversationInfo =
+ packageData != null ? packageData.getConversationInfo(shortcutId) : null;
+ if (conversationInfo != null
+ && conversationInfo.isShortcutCached()
+ && conversationInfo.getNotificationChannelId() == null) {
+ mShortcutServiceInternal.uncacheShortcuts(mUserId,
+ mContext.getPackageName(), packageName,
+ Collections.singletonList(shortcutId),
+ mUserId);
+ }
+ }
+ }
+
+ synchronized boolean hasActiveNotifications(String packageName, String shortcutId) {
+ return mActiveNotifCounts.containsKey(Pair.create(packageName, shortcutId));
+ }
}
/**
@@ -917,7 +970,16 @@
@Override
public void onReceive(Context context, Intent intent) {
- forAllUnlockedUsers(userData -> userData.forAllPackages(PackageData::saveToDisk));
+ forAllUnlockedUsers(userData -> {
+ NotificationListener listener = mNotificationListeners.get(userData.getUserId());
+ // Clean up the cached shortcuts because all the notifications are cleared after
+ // system shutdown. The associated shortcuts need to be uncached to keep in sync
+ // unless the settings are changed by the user.
+ if (listener != null) {
+ listener.cleanupCachedShortcuts();
+ }
+ userData.forAllPackages(PackageData::saveToDisk);
+ });
}
}
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index d09d0b3..43acd45 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -27,6 +27,8 @@
import android.content.IntentFilter;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
+import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
@@ -45,6 +47,8 @@
*/
class ShareTargetPredictor extends AppTargetPredictor {
+ private static final String TAG = "ShareTargetPredictor";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final IntentFilter mIntentFilter;
ShareTargetPredictor(@NonNull AppPredictionContext predictionContext,
@@ -59,6 +63,9 @@
@WorkerThread
@Override
void reportAppTargetEvent(AppTargetEvent event) {
+ if (DEBUG) {
+ Slog.d(TAG, "reportAppTargetEvent");
+ }
getDataManager().reportShareTargetEvent(event, mIntentFilter);
}
@@ -66,6 +73,9 @@
@WorkerThread
@Override
void predictTargets() {
+ if (DEBUG) {
+ Slog.d(TAG, "predictTargets");
+ }
List<ShareTarget> shareTargets = getDirectShareTargets();
SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter),
System.currentTimeMillis());
@@ -82,6 +92,9 @@
@WorkerThread
@Override
void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
+ if (DEBUG) {
+ Slog.d(TAG, "sortTargets");
+ }
List<ShareTarget> shareTargets = getAppShareTargets(targets);
SharesheetModelScorer.computeScoreForAppShare(shareTargets,
getShareEventType(mIntentFilter), getPredictionContext().getPredictedTargetCount(),
@@ -89,7 +102,15 @@
mCallingUserId);
Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
List<AppTarget> appTargetList = new ArrayList<>();
- shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
+ for (ShareTarget shareTarget : shareTargets) {
+ AppTarget appTarget = shareTarget.getAppTarget();
+ appTargetList.add(new AppTarget.Builder(appTarget.getId(), appTarget.getPackageName(),
+ appTarget.getUser())
+ .setClassName(appTarget.getClassName())
+ .setRank(shareTarget.getScore() > 0 ? (int) (shareTarget.getScore()
+ * 1000) : 0)
+ .build());
+ }
callback.accept(appTargetList);
}
diff --git a/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
index 0ac5724..76f252e 100644
--- a/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
+++ b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
@@ -50,6 +50,7 @@
private static final float RECENCY_SCORE_SUBSEQUENT_DECAY = 0.02F;
private static final long ONE_MONTH_WINDOW = TimeUnit.DAYS.toMillis(30);
private static final long FOREGROUND_APP_PROMO_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10);
+ private static final float FREQUENTLY_USED_APP_SCORE_INITIAL_DECAY = 0.3F;
private static final float FREQUENTLY_USED_APP_SCORE_DECAY = 0.9F;
@VisibleForTesting
static final float FOREGROUND_APP_WEIGHT = 0F;
@@ -219,6 +220,7 @@
Map<String, Integer> appLaunchCountsMap = dataManager.queryAppLaunchCount(
callingUserId, now - ONE_MONTH_WINDOW, now, shareTargetMap.keySet());
List<Pair<String, Integer>> appLaunchCounts = new ArrayList<>();
+ minValidScore *= FREQUENTLY_USED_APP_SCORE_INITIAL_DECAY;
for (Map.Entry<String, Integer> entry : appLaunchCountsMap.entrySet()) {
if (entry.getValue() > 0) {
appLaunchCounts.add(new Pair(entry.getKey(), entry.getValue()));
@@ -233,8 +235,8 @@
if (target.getScore() > 0f) {
continue;
}
- minValidScore *= FREQUENTLY_USED_APP_SCORE_DECAY;
target.setScore(minValidScore);
+ minValidScore *= FREQUENTLY_USED_APP_SCORE_DECAY;
if (DEBUG) {
Slog.d(TAG, String.format(
"SharesheetModel: promoteFrequentUsedApps packageName: %s, className: %s,"
diff --git a/services/print/Android.bp b/services/print/Android.bp
index aad24d7..93b5ef0 100644
--- a/services/print/Android.bp
+++ b/services/print/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.print",
+ defaults: ["services_defaults"],
srcs: [":services.print-sources"],
libs: ["services.core"],
}
diff --git a/services/restrictions/Android.bp b/services/restrictions/Android.bp
index 805858f..2883095 100644
--- a/services/restrictions/Android.bp
+++ b/services/restrictions/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.restrictions",
+ defaults: ["services_defaults"],
srcs: [":services.restrictions-sources"],
libs: ["services.core"],
}
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
index 093b4ec..46a81aae 100644
--- a/services/startop/Android.bp
+++ b/services/startop/Android.bp
@@ -16,6 +16,7 @@
java_library_static {
name: "services.startop",
+ defaults: ["services_defaults"],
static_libs: [
// frameworks/base/startop/iorap
diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp
index 1ce3e66..54968c0 100644
--- a/services/systemcaptions/Android.bp
+++ b/services/systemcaptions/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.systemcaptions",
+ defaults: ["services_defaults"],
srcs: [":services.systemcaptions-sources"],
libs: ["services.core"],
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 6d15302..8abddc8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -308,7 +308,7 @@
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
doReturn(new int[] { 0 }).when(
() -> SurfaceControl.getDisplayColorModes(display.token));
- doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f))
+ doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f))
.when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
}
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 c8ec7b5..d8874e4 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
@@ -291,7 +291,6 @@
private JobStatus createJobStatus(String testTag, int jobId) {
JobInfo jobInfo = new JobInfo.Builder(jobId,
new ComponentName(mContext, "TestQuotaJobService"))
- .setMinimumLatency(Math.abs(jobId) + 1)
.build();
return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
}
@@ -302,6 +301,9 @@
jobInfo, callingUid, packageName, SOURCE_USER_ID, testTag);
// Make sure tests aren't passing just because the default bucket is likely ACTIVE.
js.setStandbyBucket(FREQUENT_INDEX);
+ // Make sure Doze and background-not-restricted don't affect tests.
+ js.setDeviceNotDozingConstraintSatisfied(/* state */ true, /* whitelisted */false);
+ js.setBackgroundNotRestrictedConstraintSatisfied(true);
return js;
}
@@ -649,6 +651,7 @@
assertEquals(expectedStats, inputStats);
assertTrue(mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
RARE_INDEX));
+ assertTrue("Job not ready: " + jobStatus, jobStatus.isReady());
}
// Add old session. Make sure values are combined correctly.
@@ -689,6 +692,7 @@
assertEquals(expectedStats, inputStats);
assertFalse(
mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX));
+ assertFalse("Job unexpectedly ready: " + jobStatus, jobStatus.isReady());
}
/**
@@ -1325,6 +1329,7 @@
assertEquals(2, mQuotaController.getExecutionStatsLocked(
SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX).jobCountInRateLimitingWindow);
assertTrue(mQuotaController.isWithinQuotaLocked(jobStatus));
+ assertTrue(jobStatus.isReady());
}
@Test
@@ -1387,7 +1392,9 @@
mQuotaController.maybeStopTrackingJobLocked(unaffected, null, false);
assertTrue(mQuotaController.isWithinQuotaLocked(unaffected));
+ assertTrue(unaffected.isReady());
assertFalse(mQuotaController.isWithinQuotaLocked(fgStateChanger));
+ assertFalse(fgStateChanger.isReady());
assertEquals(1,
mQuotaController.getTimingSessions(SOURCE_USER_ID, unaffectedPkgName).size());
assertEquals(42,
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk
index cc1f68c..ff25a4a 100644
--- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk
+++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 2ce70b6f..b6cf278 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -129,8 +129,11 @@
public void bind_requestsContextToBindService() {
mConnection.bindLocked();
verify(mMockContext).bindServiceAsUser(any(Intent.class), eq(mConnection),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS), any(UserHandle.class));
+ eq(Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_INCLUDE_CAPABILITIES),
+ any(UserHandle.class));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
index 41142f6..98bc067 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
@@ -110,6 +110,22 @@
// We should not be getting any callbacks
verifyNoMoreInteractions(listener);
+
+ // Start watching op again
+ appOpsManager.startWatchingActive(new String[] {AppOpsManager.OPSTR_CAMERA},
+ getContext().getMainExecutor(), listener);
+
+ // Start the op
+ appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+ // We should get the callback again (and since we reset the listener, we therefore expect 1)
+ verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+ .times(1)).onOpActiveChanged(eq(AppOpsManager.OPSTR_CAMERA),
+ eq(Process.myUid()), eq(getContext().getPackageName()), eq(true));
+
+ // Finish up
+ appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+ appOpsManager.stopWatchingActive(listener);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index 96f329b..1e602f8 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -16,26 +16,26 @@
package com.android.server.appops;
-import android.Manifest;
-import android.app.AppOpsManager;
-import android.app.AppOpsManager.OnOpNotedListener;
-import android.content.Context;
-import android.os.Process;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-
-
-import static org.junit.Assert.fail;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpNotedListener;
+import android.content.Context;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
/**
* Tests watching noted ops.
*/
@@ -77,6 +77,27 @@
// This should be the only two callbacks we got
verifyNoMoreInteractions(listener);
+
+ // Note the op again and verify it isn't being watched
+ appOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION);
+ verifyNoMoreInteractions(listener);
+
+ // Start watching again
+ appOpsManager.startWatchingNoted(new int[]{AppOpsManager.OP_FINE_LOCATION,
+ AppOpsManager.OP_CAMERA}, listener);
+
+ // Note the op again
+ appOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION, Process.myUid(),
+ getContext().getPackageName());
+
+ // Verify it's watched again
+ verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+ .times(2)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION),
+ eq(Process.myUid()), eq(getContext().getPackageName()),
+ eq(AppOpsManager.MODE_ALLOWED));
+
+ // Finish up
+ appOpsManager.stopWatchingNoted(listener);
}
private static Context getContext() {
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
new file mode 100644
index 0000000..1aa697b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpStartedListener;
+import android.content.Context;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
+/** Tests watching started ops. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppOpsStartedWatcherTest {
+
+ private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
+
+ @Test
+ public void testWatchStartedOps() {
+ // Create a mock listener
+ final OnOpStartedListener listener = mock(OnOpStartedListener.class);
+
+ // Start watching started ops
+ final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ appOpsManager.startWatchingStarted(new int[]{AppOpsManager.OP_FINE_LOCATION,
+ AppOpsManager.OP_CAMERA}, listener);
+
+ // Start some ops
+ appOpsManager.startOp(AppOpsManager.OP_FINE_LOCATION);
+ appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+ appOpsManager.startOp(AppOpsManager.OP_RECORD_AUDIO);
+
+ // Verify that we got called for the ops being started
+ final InOrder inOrder = inOrder(listener);
+ inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+ .times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
+ eq(Process.myUid()), eq(getContext().getPackageName()),
+ eq(AppOpsManager.MODE_ALLOWED));
+ inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+ .times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
+ eq(Process.myUid()), eq(getContext().getPackageName()),
+ eq(AppOpsManager.MODE_ALLOWED));
+
+ // Stop watching
+ appOpsManager.stopWatchingStarted(listener);
+
+ // This should be the only two callbacks we got
+ verifyNoMoreInteractions(listener);
+
+ // Start the op again and verify it isn't being watched
+ appOpsManager.startOp(AppOpsManager.OP_FINE_LOCATION);
+ appOpsManager.finishOp(AppOpsManager.OP_FINE_LOCATION);
+ verifyNoMoreInteractions(listener);
+
+ // Start watching an op again (only CAMERA this time)
+ appOpsManager.startWatchingStarted(new int[]{AppOpsManager.OP_CAMERA}, listener);
+
+ // Note the ops again
+ appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+ appOpsManager.startOp(AppOpsManager.OP_FINE_LOCATION);
+
+ // Verify it's watched again
+ verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+ .times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
+ eq(Process.myUid()), eq(getContext().getPackageName()),
+ eq(AppOpsManager.MODE_ALLOWED));
+ verifyNoMoreInteractions(listener);
+
+ // Finish up
+ appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+ appOpsManager.finishOp(AppOpsManager.OP_FINE_LOCATION);
+ appOpsManager.stopWatchingStarted(listener);
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index d292526..285caf3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -186,7 +186,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -269,7 +270,8 @@
eq(false) /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -407,7 +409,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Hardware authenticated
final byte[] HAT = generateRandomHAT();
@@ -462,7 +465,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -610,7 +614,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
anyString(),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -711,7 +716,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test
@@ -1207,7 +1213,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Requesting strong and credential, when credential is setup
resetReceiver();
@@ -1227,7 +1234,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
// Un-downgrading the authenticator allows successful strong auth
for (BiometricService.AuthenticatorWrapper wrapper : mBiometricService.mAuthenticators) {
@@ -1250,7 +1258,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ anyInt() /* sysUiSessionId */);
}
@Test(expected = IllegalStateException.class)
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c228508..ed40fe7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -17,6 +17,7 @@
import static android.app.Notification.EXTRA_TEXT;
import static android.app.Notification.EXTRA_TITLE;
+import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
@@ -32,6 +33,9 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
+import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
+import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
+import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
@@ -220,7 +224,7 @@
// Make createContextAsUser to work.
mContext.packageName = "com.android.frameworks.servicestests";
getServices().addPackageContext(UserHandle.of(0), mContext);
- getServices().addPackageContext(UserHandle.of(DpmMockContext.CALLER_USER_HANDLE), mContext);
+ getServices().addPackageContext(UserHandle.of(CALLER_USER_HANDLE), mContext);
// By default, pretend all users are running and unlocked.
when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);
@@ -321,22 +325,21 @@
anyString(), any(UserHandle.class));
// Add the first secondary user.
- getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
- UserManager.USER_TYPE_FULL_SECONDARY);
+ getServices().addUser(CALLER_USER_HANDLE, 0, UserManager.USER_TYPE_FULL_SECONDARY);
}
private void setAsProfileOwner(ComponentName admin) {
final long ident = mServiceContext.binder.clearCallingIdentity();
mServiceContext.binder.callingUid =
- UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
+ UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
runAsCaller(mServiceContext, dpms, dpm -> {
// PO needs to be a DA.
dpm.setActiveAdmin(admin, /*replace=*/ false);
// Fire!
- assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+ assertTrue(dpm.setProfileOwner(admin, "owner-name", CALLER_USER_HANDLE));
// Check
- assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
+ assertEquals(admin, dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE));
});
mServiceContext.binder.restoreCallingIdentity(ident);
@@ -360,12 +363,10 @@
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
setAsProfileOwner(admin2);
// Active admin in CALLER_USER_HANDLE
- final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 1306);
+ final int ANOTHER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 1306);
setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
- dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false,
- DpmMockContext.CALLER_USER_HANDLE);
- assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage,
- DpmMockContext.CALLER_USER_HANDLE));
+ dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false, CALLER_USER_HANDLE);
+ assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage, CALLER_USER_HANDLE));
initializeDpms();
@@ -376,7 +377,7 @@
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
MockUtils.checkApps(admin2.getPackageName(),
adminAnotherPackage.getPackageName()),
- eq(DpmMockContext.CALLER_USER_HANDLE));
+ eq(CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
}
@@ -389,7 +390,7 @@
// Verify
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
null, ANOTHER_USER_ID);
verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
@@ -410,7 +411,7 @@
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1));
+ () -> dpm.setActiveAdmin(admin1, false, CALLER_USER_HANDLE + 1));
}
/**
@@ -435,11 +436,11 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
eq(null),
any(Bundle.class));
@@ -447,11 +448,11 @@
eq(admin1.getPackageName()),
eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
eq(PackageManager.DONT_KILL_APP),
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
anyString());
verify(getServices().usageStatsManagerInternal).onActiveAdminAdded(
- admin1.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+ admin1.getPackageName(), CALLER_USER_HANDLE);
// TODO Verify other calls too.
@@ -466,8 +467,8 @@
// (Because we're checking a different user's status from CALLER_USER_HANDLE.)
mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
- assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE + 1));
+ assertFalse(dpm.isAdminActiveAsUser(admin2, CALLER_USER_HANDLE + 1));
mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
@@ -489,13 +490,13 @@
eq(admin1.getPackageName()),
eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
eq(PackageManager.DONT_KILL_APP),
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
anyString());
// times(2) because it was previously called for admin1 which is in the same package
// as admin2.
verify(getServices().usageStatsManagerInternal, times(2)).onActiveAdminAdded(
- admin2.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);
+ admin2.getPackageName(), CALLER_USER_HANDLE);
// 4. Add the same admin1 again without replace, which should throw.
assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
@@ -520,7 +521,7 @@
mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
- dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
+ dpm.getActiveAdminsAsUser(CALLER_USER_HANDLE + 1)));
mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
}
@@ -606,11 +607,11 @@
assertTrue(dpm.isAdminActive(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// Directly call the DPMS method with a different userid, which should fail.
assertExpectException(SecurityException.class, /* messageRegex =*/ null,
- () -> dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
+ () -> dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE + 1));
// Try to remove active admin with a different caller userid should fail too, without
// having MANAGE_DEVICE_ADMINS.
@@ -620,7 +621,7 @@
mContext.binder.callingUid = 1234567;
assertExpectException(SecurityException.class, /* messageRegex =*/ null,
- () -> dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ () -> dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE));
}
/**
@@ -638,27 +639,25 @@
assertTrue(dpm.isAdminActive(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// 1. User not unlocked.
- when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
- .thenReturn(false);
+ setUserUnlocked(CALLER_USER_HANDLE, false);
assertExpectException(IllegalStateException.class,
/* messageRegex= */ "User must be running and unlocked",
() -> dpm.removeActiveAdmin(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
// 2. User unlocked.
- when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
- .thenReturn(true);
+ setUserUnlocked(CALLER_USER_HANDLE, true);
dpm.removeActiveAdmin(admin1);
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
}
/**
@@ -673,7 +672,7 @@
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.isAdminActive(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// Different user, but should work, because caller has proper permissions.
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -681,10 +680,10 @@
// Change the caller, and call into DPMS directly with a different user-id.
mContext.binder.callingUid = 1234567;
- dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE);
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
// TODO DO Still can't be removed in this case.
}
@@ -702,13 +701,13 @@
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.isAdminActive(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// Broadcast from saveSettingsLocked().
verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
// Remove. No permissions, but same user, so it'll work.
mContext.callerPermissions.clear();
@@ -717,7 +716,7 @@
verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
MockUtils.checkIntentAction(
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
isNull(String.class),
eq(AppOpsManager.OP_NONE),
any(Bundle.class),
@@ -727,15 +726,15 @@
isNull(String.class),
isNull(Bundle.class));
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
// Again broadcast from saveSettingsLocked().
verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
// TODO Check other internal calls.
}
@@ -748,19 +747,19 @@
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.isAdminActive(admin1));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// Add admin2.
dpm.setActiveAdmin(admin2, /* replace =*/ false);
assertTrue(dpm.isAdminActive(admin2));
- assertFalse(dpm.isRemovingAdmin(admin2, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin2, CALLER_USER_HANDLE));
// Broadcast from saveSettingsLocked().
verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
// Remove. No permissions, but same user, so it'll work.
mContext.callerPermissions.clear();
@@ -769,7 +768,7 @@
verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
MockUtils.checkIntentAction(
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
isNull(String.class),
eq(AppOpsManager.OP_NONE),
any(Bundle.class),
@@ -779,16 +778,16 @@
isNull(String.class),
isNull(Bundle.class));
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
MockUtils.checkApps(admin2.getPackageName()),
- eq(DpmMockContext.CALLER_USER_HANDLE));
+ eq(CALLER_USER_HANDLE));
// Again broadcast from saveSettingsLocked().
verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
}
/**
@@ -800,7 +799,7 @@
// Add admin.
setupPackageInPackageManager(admin1.getPackageName(),
- /* userId= */ DpmMockContext.CALLER_USER_HANDLE,
+ /* userId= */ CALLER_USER_HANDLE,
/* appId= */ 10138,
/* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
dpm.setActiveAdmin(admin1, /* replace =*/ false);
@@ -810,16 +809,16 @@
mContext.binder.callingUid = 123456;
assertExpectException(SecurityException.class,
/* messageRegex =*/ "Non-shell user attempted to call",
- () -> dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ () -> dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE));
mContext.binder.callingUid = Process.SHELL_UID;
- dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);
mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
// Verify
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
}
/**
@@ -1244,12 +1243,12 @@
setAsProfileOwner(admin1);
verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
- eq(DpmMockContext.CALLER_USER_HANDLE), eq(false));
+ eq(CALLER_USER_HANDLE), eq(false));
dpm.clearProfileOwner(admin1);
verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
- eq(DpmMockContext.CALLER_USER_HANDLE), eq(true));
+ eq(CALLER_USER_HANDLE), eq(true));
}
public void testClearDeviceOwner_fromDifferentUser() throws Exception {
@@ -1341,11 +1340,11 @@
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.setActiveAdmin(admin2, /* refreshing= */ true, DpmMockContext.CALLER_USER_HANDLE);
+ dpm.setActiveAdmin(admin2, /* refreshing= */ true, CALLER_USER_HANDLE);
assertExpectException(IllegalStateException.class,
/* messageRegex= */ "already has a profile owner",
() -> dpm.setDeviceOwner(admin2, "owner-name",
- DpmMockContext.CALLER_USER_HANDLE));
+ CALLER_USER_HANDLE));
});
}
@@ -1355,7 +1354,7 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName()));
- assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE));
// First try when the user is locked, which should fail.
when(getServices().userManager.isUserUnlocked(anyInt()))
@@ -1370,9 +1369,9 @@
// Check
assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
- assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- null, DpmMockContext.CALLER_USER_HANDLE);
+ null, CALLER_USER_HANDLE);
}
public void testSetProfileOwner_failures() throws Exception {
@@ -1416,14 +1415,14 @@
dpm.setActiveAdmin(admin1, /* replace =*/ false);
dpm.setActiveAdmin(admin3, /* replace =*/ false);
- dpm.setActiveAdmin(admin1, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
- dpm.setActiveAdmin(admin2, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
+ dpm.setActiveAdmin(admin1, /* replace =*/ false, CALLER_USER_HANDLE);
+ dpm.setActiveAdmin(admin2, /* replace =*/ false, CALLER_USER_HANDLE);
dpm.setActiveAdmin(admin2, /* replace =*/ false, ANOTHER_USER_ID);
// Set DO on the first non-system user.
- getServices().setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
- assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+ getServices().setUserRunning(CALLER_USER_HANDLE, true);
+ assertTrue(dpm.setDeviceOwner(admin2, "owner-name", CALLER_USER_HANDLE));
assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
@@ -1447,7 +1446,7 @@
// Overwrite the device owner setting and clears the clas name.
dpms.mOwners.setDeviceOwner(
new ComponentName(admin2.getPackageName(), ""),
- "owner-name", DpmMockContext.CALLER_USER_HANDLE);
+ "owner-name", CALLER_USER_HANDLE);
dpms.mOwners.writeDeviceOwner();
// Make sure the DO component name doesn't have a class name.
@@ -1508,7 +1507,7 @@
*/
private int setupPackageInPackageManager(final String packageName, final int appId)
throws Exception {
- return setupPackageInPackageManager(packageName, DpmMockContext.CALLER_USER_HANDLE, appId,
+ return setupPackageInPackageManager(packageName, CALLER_USER_HANDLE, appId,
ApplicationInfo.FLAG_HAS_CODE);
}
@@ -1549,7 +1548,7 @@
}
public void testCertificateDisclosure() throws Exception {
- final int userId = DpmMockContext.CALLER_USER_HANDLE;
+ final int userId = CALLER_USER_HANDLE;
final UserHandle user = UserHandle.of(userId);
mContext.applicationInfo = new ApplicationInfo();
@@ -1591,7 +1590,7 @@
public void testDelegation() throws Exception {
setAsProfileOwner(admin1);
- final int userHandle = DpmMockContext.CALLER_USER_HANDLE;
+ final int userHandle = CALLER_USER_HANDLE;
// Given two packages
final String CERT_DELEGATE = "com.delegate.certs";
@@ -1895,23 +1894,22 @@
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
- .ensureUserRestrictions()
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE).ensureUserRestrictions()
);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
eq(false));
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS),
eq(false));
@@ -1921,7 +1919,7 @@
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS
),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
DpmTestUtils.assertRestrictions(
@@ -1934,9 +1932,9 @@
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
UserManager.DISALLOW_OUTGOING_CALLS),
eq(false));
@@ -1944,7 +1942,7 @@
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_OUTGOING_CALLS
),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
DpmTestUtils.assertRestrictions(
@@ -1956,13 +1954,13 @@
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE), eq(false));
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE), eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
DpmTestUtils.assertRestrictions(
@@ -1976,18 +1974,18 @@
dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
eq(false));
dpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
UserManager.DISALLOW_CAMERA),
@@ -2000,7 +1998,6 @@
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
Sets.newSet(
UserManager.DISALLOW_CONFIG_DATE_TIME,
- UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_BLUETOOTH_SHARING,
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -2029,13 +2026,13 @@
public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
final int MANAGED_PROFILE_ADMIN_UID =
- UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
+ UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
- when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE))
+ when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS) {
@@ -2047,13 +2044,13 @@
parentDpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE),
eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.getParentActiveAdmin()
.getEffectiveRestrictions()
);
@@ -2061,7 +2058,7 @@
parentDpm.setCameraDisabled(admin1, false);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.getParentActiveAdmin()
.getEffectiveRestrictions()
);
@@ -2071,14 +2068,14 @@
private void addAndRemoveGlobalUserRestrictionOnParentDpm(String restriction) {
parentDpm.addUserRestriction(admin1, restriction);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(restriction),
- MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserRestrictions(CALLER_USER_HANDLE),
eq(false));
parentDpm.clearUserRestriction(admin1, restriction);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.getParentActiveAdmin()
.getEffectiveRestrictions()
);
@@ -2087,14 +2084,14 @@
private void addAndRemoveLocalUserRestrictionOnParentDpm(String restriction) {
parentDpm.addUserRestriction(admin1, restriction);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(DpmMockContext.CALLER_USER_HANDLE),
+ eq(CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM, restriction),
eq(false));
parentDpm.clearUserRestriction(admin1, restriction);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
- dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+ dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
.getParentActiveAdmin()
.getEffectiveRestrictions()
);
@@ -2155,7 +2152,7 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
@@ -2173,7 +2170,7 @@
public void testSetFactoryResetProtectionPolicyWithPOOfOrganizationOwnedDevice()
throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn(
DpmMockContext.CALLER_UID);
@@ -2195,15 +2192,15 @@
verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
@@ -2231,7 +2228,7 @@
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
- MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE),
eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
@@ -2269,13 +2266,13 @@
public void testSetKeyguardDisabledFeaturesWithPOOfOrganizationOwnedDevice()
throws Exception {
- final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
+ final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
parentDpm.setKeyguardDisabledFeatures(admin1,
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
@@ -2308,13 +2305,13 @@
}
public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
- final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
+ final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
mContext.packageName = admin1.getPackageName();
setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
@@ -2388,7 +2385,7 @@
public void testGetMacAddressByOrgOwnedPO() throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
@@ -2450,21 +2447,17 @@
assertNull(dpm.getLongSupportMessage(admin1));
assertNull(dpm.getShortSupportMessage(admin1));
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- assertNull(dpm.getShortSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
- assertNull(dpm.getLongSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE));
mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
// Only system can call the per user versions.
{
assertExpectException(SecurityException.class, /* messageRegex= */ "message for user",
- () -> dpm.getShortSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
+ () -> dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE));
assertExpectException(SecurityException.class, /* messageRegex= */ "message for user",
- () -> dpm.getLongSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
+ () -> dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE));
}
// Can't set message for admin in another uid.
@@ -2486,11 +2479,9 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
- assertNull(dpm.getShortSupportMessageForUser(admin2,
- DpmMockContext.CALLER_USER_HANDLE));
- assertNull(dpm.getLongSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
+ CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin2, CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE));
mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
dpm.setShortSupportMessage(admin1, null);
@@ -2507,11 +2498,9 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
- assertNull(dpm.getLongSupportMessageForUser(admin2,
- DpmMockContext.CALLER_USER_HANDLE));
- assertNull(dpm.getShortSupportMessageForUser(admin1,
- DpmMockContext.CALLER_USER_HANDLE));
+ CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin2, CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE));
mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
dpm.setLongSupportMessage(admin1, null);
@@ -2531,8 +2520,8 @@
final String package2 = "com.example.two";
pkgsToRestrict.add(package1);
pkgsToRestrict.add(package2);
- setupPackageInPackageManager(package1, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
- setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
+ setupPackageInPackageManager(package1, CALLER_USER_HANDLE, 123, 0);
+ setupPackageInPackageManager(package2, CALLER_USER_HANDLE, 456, 0);
List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);
// Verify
@@ -2540,7 +2529,7 @@
assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabledPackages(admin1));
verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
- eq(DpmMockContext.CALLER_USER_HANDLE));
+ eq(CALLER_USER_HANDLE));
// Setup
pkgsToRestrict.remove(package1);
@@ -2551,7 +2540,7 @@
assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabledPackages(admin1));
verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
- eq(DpmMockContext.CALLER_USER_HANDLE));
+ eq(CALLER_USER_HANDLE));
}
public void testSetGetMeteredDataDisabledPackages_deviceAdmin() {
@@ -2577,22 +2566,19 @@
final String package3 = "com.example.three";
pkgsToRestrict.add(package1);
pkgsToRestrict.add(package2);
- setupPackageInPackageManager(package1, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
- setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
+ setupPackageInPackageManager(package1, CALLER_USER_HANDLE, 123, 0);
+ setupPackageInPackageManager(package2, CALLER_USER_HANDLE, 456, 0);
List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);
// Verify
assertEquals(emptyList, excludedPkgs);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertTrue(package1 + "should be restricted",
- dpm.isMeteredDataDisabledPackageForUser(admin1, package1,
- DpmMockContext.CALLER_USER_HANDLE));
+ dpm.isMeteredDataDisabledPackageForUser(admin1, package1, CALLER_USER_HANDLE));
assertTrue(package2 + "should be restricted",
- dpm.isMeteredDataDisabledPackageForUser(admin1, package2,
- DpmMockContext.CALLER_USER_HANDLE));
+ dpm.isMeteredDataDisabledPackageForUser(admin1, package2, CALLER_USER_HANDLE));
assertFalse(package3 + "should not be restricted",
- dpm.isMeteredDataDisabledPackageForUser(admin1, package3,
- DpmMockContext.CALLER_USER_HANDLE));
+ dpm.isMeteredDataDisabledPackageForUser(admin1, package3, CALLER_USER_HANDLE));
}
public void testIsMeteredDataDisabledForUserPackage_nonSystemUidCaller() throws Exception {
@@ -2600,14 +2586,14 @@
assertExpectException(SecurityException.class,
/* messageRegex= */ "Only the system can query restricted pkgs",
() -> dpm.isMeteredDataDisabledPackageForUser(
- admin1, "com.example.one", DpmMockContext.CALLER_USER_HANDLE));
+ admin1, "com.example.one", CALLER_USER_HANDLE));
dpm.clearProfileOwner(admin1);
setDeviceOwner();
assertExpectException(SecurityException.class,
/* messageRegex= */ "Only the system can query restricted pkgs",
() -> dpm.isMeteredDataDisabledPackageForUser(
- admin1, "com.example.one", DpmMockContext.CALLER_USER_HANDLE));
+ admin1, "com.example.one", CALLER_USER_HANDLE));
clearDeviceOwner();
}
@@ -2774,7 +2760,7 @@
public void testSetUserProvisioningState_permission() throws Exception {
setupProfileOwner();
- exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
@@ -2782,7 +2768,7 @@
setupProfileOwner();
assertExpectException(SecurityException.class, /* messageRegex =*/ null,
() -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
- DpmMockContext.CALLER_USER_HANDLE));
+ CALLER_USER_HANDLE));
}
public void testSetUserProvisioningState_noManagement() {
@@ -2791,7 +2777,7 @@
assertExpectException(IllegalStateException.class,
/* messageRegex= */ "change provisioning state unless a .* owner is set",
() -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
- DpmMockContext.CALLER_USER_HANDLE));
+ CALLER_USER_HANDLE));
assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
}
@@ -2826,7 +2812,7 @@
throws Exception {
setupProfileOwner();
- exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
DevicePolicyManager.STATE_USER_UNMANAGED);
}
@@ -2835,7 +2821,7 @@
throws Exception {
setupProfileOwner();
- exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
@@ -2843,7 +2829,7 @@
public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
setupProfileOwner();
- exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
@@ -2852,7 +2838,7 @@
assertExpectException(IllegalStateException.class,
/* messageRegex= */ "Cannot move to user provisioning state",
- () -> exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ () -> exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
DevicePolicyManager.STATE_USER_UNMANAGED));
}
@@ -2863,7 +2849,7 @@
assertExpectException(IllegalStateException.class,
/* messageRegex= */ "Cannot move to user provisioning state",
- () -> exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+ () -> exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
DevicePolicyManager.STATE_USER_SETUP_COMPLETE));
}
@@ -2884,7 +2870,7 @@
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
dpm.setActiveAdmin(admin1, false);
- assertTrue(dpm.setProfileOwner(admin1, null, DpmMockContext.CALLER_USER_HANDLE));
+ assertTrue(dpm.setProfileOwner(admin1, null, CALLER_USER_HANDLE));
mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
}
@@ -3552,9 +3538,9 @@
when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
.thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
true)).thenReturn(true);
- setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+ setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
@@ -3592,9 +3578,9 @@
when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
.thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
true)).thenReturn(true);
- setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
+ setUserSetupCompleteForUser(true, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
@@ -3668,11 +3654,11 @@
when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
.thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
- when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE))
+ when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
- when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
true)).thenReturn(true);
- setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+ setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
}
@@ -3703,13 +3689,13 @@
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
when(getServices().userManager.hasUserRestriction(
eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
- eq(UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))))
+ eq(UserHandle.of(CALLER_USER_HANDLE))))
.thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
false /* we can't remove a managed profile */)).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
true)).thenReturn(true);
- setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+ setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
@@ -3817,7 +3803,7 @@
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
- getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
+ getServices().removeUser(CALLER_USER_HANDLE);
when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs))
.thenReturn(true);
@@ -3902,7 +3888,7 @@
public void testSetConfiguredNetworksLockdownStateWithPOOfOrganizationOwnedDevice()
throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
dpm.setConfiguredNetworksLockdownState(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 1);
@@ -3931,7 +3917,7 @@
setupProfileOwner();
dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
verify(getServices().settings).settingsSystemPutStringForUser(
- Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE);
+ Settings.System.SCREEN_BRIGHTNESS, "0", CALLER_USER_HANDLE);
}
public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
@@ -3963,7 +3949,7 @@
public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
dpm.setAutoTimeEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
@@ -4002,7 +3988,7 @@
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
dpm.setAutoTimeZoneEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
@@ -4017,7 +4003,13 @@
// Any caller should be able to call this method.
assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_ADD_USER),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
// A random caller from another user should also be able to get the right result.
@@ -4025,6 +4017,35 @@
assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
}
+ public void testMarkOrganizationOwnedDevice_baseRestrictionsAdded() throws Exception {
+ addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
+
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+
+ // Base restriction DISALLOW_REMOVE_MANAGED_PROFILE added
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
+ // Base restriction DISALLOW_ADD_USER added
+ verify(getServices().userManager).setUserRestriction(
+ eq(UserManager.DISALLOW_ADD_USER),
+ eq(true),
+ eq(UserHandle.of(UserHandle.USER_SYSTEM)));
+
+ // Assert base restrictions cannot be added or removed by admin
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.clearUserRestriction(admin1,
+ UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
+ assertExpectException(SecurityException.class, null, () ->
+ parentDpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4039,7 +4060,7 @@
public void testSetTimeWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
dpm.setTime(admin1, 0);
verify(getServices().alarmManager).setTime(0);
}
@@ -4067,7 +4088,7 @@
public void testSetTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
dpm.setTimeZone(admin1, "Asia/Shanghai");
verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
}
@@ -4093,7 +4114,7 @@
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
- getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
+ getServices().removeUser(CALLER_USER_HANDLE);
// No bug reports were requested so far.
assertEquals(-1, dpm.getLastBugReportRequestTime());
@@ -4141,7 +4162,7 @@
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
- getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
+ getServices().removeUser(CALLER_USER_HANDLE);
when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
.thenReturn(true);
@@ -4273,13 +4294,13 @@
// Setup a PO
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setAsProfileOwner(admin1);
- verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE);
+ verifyLockTaskState(CALLER_USER_HANDLE);
final String[] poPackages = {"poPackage1", "poPackage2"};
final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
| DevicePolicyManager.LOCK_TASK_FEATURE_HOME
| DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
- verifyCanSetLockTask(DpmMockContext.CALLER_UID, DpmMockContext.CALLER_USER_HANDLE, admin1,
+ verifyCanSetLockTask(DpmMockContext.CALLER_UID, CALLER_USER_HANDLE, admin1,
poPackages, poFlags);
// Set up a managed profile managed by different package (package name shouldn't matter)
@@ -4318,7 +4339,7 @@
// Initial state is disabled.
assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ CALLER_USER_HANDLE)));
// Profile owner can set enabled state.
setAsProfileOwner(admin1);
@@ -4327,7 +4348,7 @@
.thenReturn(admin1.flattenToString());
dpm.setSecondaryLockscreenEnabled(admin1, true);
assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ CALLER_USER_HANDLE)));
// Managed profile managed by different package is unaffiliated - cannot set enabled.
final int managedProfileUserId = 15;
@@ -4359,8 +4380,7 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Initial state is disabled.
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
// Non-DO/PO cannot set enabled state.
when(mServiceContext.resources
@@ -4368,23 +4388,20 @@
.thenReturn(admin1.flattenToString());
assertExpectException(SecurityException.class, /* messageRegex= */ null,
() -> dpm.setSecondaryLockscreenEnabled(admin1, true));
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
}
public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Initial state is disabled.
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
// Caller is Profile Owner, but no supervision app is configured.
setAsProfileOwner(admin1);
assertExpectException(SecurityException.class, "no default supervision component defined",
() -> dpm.setSecondaryLockscreenEnabled(admin1, true));
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
// Caller is Profile Owner, but is not the default configured supervision app.
when(mServiceContext.resources
@@ -4392,8 +4409,7 @@
.thenReturn(admin2.flattenToString());
assertExpectException(SecurityException.class, "is not the default supervision component",
() -> dpm.setSecondaryLockscreenEnabled(admin1, true));
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
- DpmMockContext.CALLER_USER_HANDLE)));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
}
public void testIsDeviceManaged() throws Exception {
@@ -4729,14 +4745,14 @@
doReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED).when(getServices().packageManager)
.getPermissionFlags(permission, app1, UserHandle.SYSTEM);
when(getServices().packageManager.getPermissionFlags(permission, app1,
- UserHandle.of(DpmMockContext.CALLER_USER_HANDLE)))
+ UserHandle.of(CALLER_USER_HANDLE)))
.thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
when(getServices().ipackageManager.checkPermission(eq(permission), eq(app2), anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
doReturn(0).when(getServices().packageManager).getPermissionFlags(permission, app2,
UserHandle.SYSTEM);
when(getServices().packageManager.getPermissionFlags(permission, app2,
- UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(0);
+ UserHandle.of(CALLER_USER_HANDLE))).thenReturn(0);
// System can retrieve permission grant state.
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -4879,7 +4895,7 @@
}
public void testIsPasswordSufficientAfterProfileUnification() throws Exception {
- final int managedProfileUserId = DpmMockContext.CALLER_USER_HANDLE;
+ final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = managedProfileAdminUid;
@@ -4955,7 +4971,7 @@
final int deviceOwnerUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
DpmMockContext.SYSTEM_UID);
- final int secondUserSystemUid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ final int secondUserSystemUid = UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.SYSTEM_UID);
// Set up a device owner.
@@ -4983,7 +4999,7 @@
assertFalse(dpm.isCurrentInputMethodSetByOwner());
// Second user changes IME manually.
- dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
+ dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
mContext.binder.callingUid = firstUserSystemUid;
assertTrue(dpm.isCurrentInputMethodSetByOwner());
mContext.binder.callingUid = secondUserSystemUid;
@@ -5034,7 +5050,7 @@
final int profileOwnerUid = DpmMockContext.CALLER_UID;
final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
DpmMockContext.SYSTEM_UID);
- final int secondUserSystemUid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ final int secondUserSystemUid = UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.SYSTEM_UID);
// Set up a profile owner.
@@ -5050,12 +5066,12 @@
// Profile owner changes IME for second user.
mContext.binder.callingUid = profileOwnerUid;
when(getServices().settings.settingsSecureGetStringForUser(currentIme,
- DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime1");
+ CALLER_USER_HANDLE)).thenReturn("ime1");
dpm.setSecureSetting(admin1, currentIme, "ime2");
verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime2",
- DpmMockContext.CALLER_USER_HANDLE);
+ CALLER_USER_HANDLE);
reset(getServices().settings);
- dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
+ dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
mContext.binder.callingUid = firstUserSystemUid;
assertFalse(dpm.isCurrentInputMethodSetByOwner());
mContext.binder.callingUid = secondUserSystemUid;
@@ -5069,7 +5085,7 @@
assertTrue(dpm.isCurrentInputMethodSetByOwner());
// Second user changes IME manually.
- dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
+ dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
mContext.binder.callingUid = firstUserSystemUid;
assertFalse(dpm.isCurrentInputMethodSetByOwner());
mContext.binder.callingUid = secondUserSystemUid;
@@ -5078,11 +5094,11 @@
// Profile owner changes IME for second user again.
mContext.binder.callingUid = profileOwnerUid;
when(getServices().settings.settingsSecureGetStringForUser(currentIme,
- DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime2");
+ CALLER_USER_HANDLE)).thenReturn("ime2");
dpm.setSecureSetting(admin1, currentIme, "ime3");
verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime3",
- DpmMockContext.CALLER_USER_HANDLE);
- dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
+ CALLER_USER_HANDLE);
+ dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
mContext.binder.callingUid = firstUserSystemUid;
assertFalse(dpm.isCurrentInputMethodSetByOwner());
mContext.binder.callingUid = secondUserSystemUid;
@@ -5337,7 +5353,7 @@
final DpmMockContext caller = new DpmMockContext(getServices(), mRealTestContext);
caller.packageName = "com.example.delegate";
caller.binder.callingUid = setupPackageInPackageManager(caller.packageName,
- DpmMockContext.CALLER_USER_HANDLE, 20988, ApplicationInfo.FLAG_HAS_CODE);
+ CALLER_USER_HANDLE, 20988, ApplicationInfo.FLAG_HAS_CODE);
// Make caller a delegated cert installer.
runAsCaller(mAdmin1Context, dpms,
@@ -5355,8 +5371,7 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
RestrictionsListener listener = new RestrictionsListener(mContext);
- listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, restriction,
- new Bundle());
+ listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, restriction, new Bundle());
verifyDataSharingChangedBroadcast();
}
@@ -5368,15 +5383,13 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
RestrictionsListener listener = new RestrictionsListener(mContext);
- listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
- restriction);
+ listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), restriction);
verifyDataSharingChangedBroadcast();
}
public void testDisallowSharingIntoProfileUnchanged() {
RestrictionsListener listener = new RestrictionsListener(mContext);
- listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
- new Bundle());
+ listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), new Bundle());
verify(mContext.spiedContext, never()).sendBroadcastAsUser(any(), any());
}
@@ -5384,7 +5397,7 @@
Intent expectedIntent = new Intent(
DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
expectedIntent.setPackage("com.android.managedprovisioning");
- expectedIntent.putExtra(Intent.EXTRA_USER_ID, DpmMockContext.CALLER_USER_HANDLE);
+ expectedIntent.putExtra(Intent.EXTRA_USER_ID, CALLER_USER_HANDLE);
verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
MockUtils.checkIntent(expectedIntent),
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -5615,9 +5628,8 @@
setupProfileOwner();
initializeDpms();
assertFalse(getMockTransferMetadataManager().metadataFileExists());
- assertTrue(dpms.isProfileOwner(admin1, DpmMockContext.CALLER_USER_HANDLE));
- assertTrue(dpms.isAdminActive(admin1, DpmMockContext.CALLER_USER_HANDLE));
- UserHandle userHandle = UserHandle.of(DpmMockContext.CALLER_USER_HANDLE);
+ assertTrue(dpms.isProfileOwner(admin1, CALLER_USER_HANDLE));
+ assertTrue(dpms.isAdminActive(admin1, CALLER_USER_HANDLE));
}
// @FlakyTest(bugId = 148934649)
@@ -5647,7 +5659,7 @@
// }
public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception {
- getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
+ getServices().addUser(CALLER_USER_HANDLE, 0,
UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
DpmTestUtils.writeInputStreamToFile(
getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated),
@@ -5679,7 +5691,7 @@
// This method will throw if the system context could not call
// markProfileOwnerOfOrganizationOwnedDevice successfully.
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
}
private void configureContextForAccess(DpmMockContext context, boolean granted) {
@@ -5699,7 +5711,7 @@
configureContextForAccess(mServiceContext, true);
mServiceContext.binder.callingUid =
- UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
try {
runAsCaller(mServiceContext, dpms, dpm -> {
@@ -5741,7 +5753,7 @@
admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID));
setupProfileOwner();
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
// The profile owner is allowed to request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -5760,7 +5772,7 @@
public void runAsDelegatedCertInstaller(DpmRunnable action) throws Exception {
final long ident = mServiceContext.binder.clearCallingIdentity();
- mServiceContext.binder.callingUid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ mServiceContext.binder.callingUid = UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.DELEGATE_CERT_INSTALLER_UID);
try {
runAsCaller(mServiceContext, dpms, action);
@@ -5778,7 +5790,7 @@
dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
Arrays.asList(DELEGATION_CERT_INSTALL)));
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
// Make sure that the profile owner can still request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -5788,7 +5800,7 @@
runAsDelegatedCertInstaller(dpm -> {
dpms.enforceCallerCanRequestDeviceIdAttestation(null,
DpmMockContext.DELEGATE_PACKAGE_NAME,
- UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.DELEGATE_CERT_INSTALLER_UID));
});
}
@@ -5813,7 +5825,7 @@
assertExpectException(SecurityException.class, /* messageRegex= */ null,
() -> dpms.enforceCallerCanRequestDeviceIdAttestation(null,
DpmMockContext.DELEGATE_PACKAGE_NAME,
- UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.DELEGATE_CERT_INSTALLER_UID)));
});
}
@@ -5834,8 +5846,7 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
new String[0]);
- when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(false);
+ when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(false);
assertThrows(IllegalStateException.class, () -> dpm.getPasswordComplexity());
}
@@ -5843,8 +5854,7 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
new String[0]);
- when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(true);
+ when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
assertThrows(SecurityException.class, () -> dpm.getPasswordComplexity());
}
@@ -5853,11 +5863,10 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
new String[0]);
- when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(true);
+ when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
- when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
+ when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
+ .thenReturn(CALLER_USER_HANDLE);
assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity());
}
@@ -5866,13 +5875,12 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
new String[0]);
- when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(true);
+ when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
- when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
+ when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
+ .thenReturn(CALLER_USER_HANDLE);
when(getServices().lockSettingsInternal
- .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
+ .getUserPasswordMetrics(CALLER_USER_HANDLE))
.thenReturn(computeForPassword("asdf".getBytes()));
assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity());
@@ -5882,17 +5890,16 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
new String[0]);
- when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
- .thenReturn(true);
+ when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
UserInfo parentUser = new UserInfo();
- parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10;
- when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
+ parentUser.id = CALLER_USER_HANDLE + 10;
+ when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
.thenReturn(parentUser.id);
when(getServices().lockSettingsInternal
- .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
+ .getUserPasswordMetrics(CALLER_USER_HANDLE))
.thenReturn(computeForPassword("asdf".getBytes()));
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(parentUser.id))
@@ -5945,7 +5952,7 @@
dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet());
when(getServices().settings.settingsSecureGetIntForUser(
Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
- 0, DpmMockContext.CALLER_USER_HANDLE)).thenReturn(1);
+ 0, CALLER_USER_HANDLE)).thenReturn(1);
assertFalse(dpm.isPackageAllowedToAccessCalendar("TEST_PACKAGE"));
}
@@ -5955,7 +5962,7 @@
dpm.setCrossProfileCalendarPackages(admin1, Collections.singleton(testPackage));
when(getServices().settings.settingsSecureGetIntForUser(
Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
- 0, DpmMockContext.CALLER_USER_HANDLE)).thenReturn(0);
+ 0, CALLER_USER_HANDLE)).thenReturn(0);
assertFalse(dpm.isPackageAllowedToAccessCalendar(testPackage));
}
@@ -5965,7 +5972,7 @@
dpm.setCrossProfileCalendarPackages(admin1, null);
when(getServices().settings.settingsSecureGetIntForUser(
Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
- 0, DpmMockContext.CALLER_USER_HANDLE)).thenReturn(1);
+ 0, CALLER_USER_HANDLE)).thenReturn(1);
assertTrue(dpm.isPackageAllowedToAccessCalendar(testPackage));
}
@@ -6149,7 +6156,7 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertFalse("po is not direct boot aware",
- dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE));
+ dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE));
}
public void testCanProfileOwnerResetPasswordWhenLocked_noActiveToken() throws Exception {
@@ -6159,7 +6166,7 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertFalse("po doesn't have an active password reset token",
- dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE));
+ dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE));
}
public void testCanProfileOwnerResetPasswordWhenLocked_nonFbeDevice() throws Exception {
@@ -6169,7 +6176,7 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertFalse("device is not FBE",
- dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE));
+ dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE));
}
public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
@@ -6180,7 +6187,7 @@
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
assertTrue("direct boot aware po with active password reset token",
- dpm.canProfileOwnerResetPasswordWhenLocked(DpmMockContext.CALLER_USER_HANDLE));
+ dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE));
}
private void setupPasswordResetToken() {
@@ -6188,14 +6195,14 @@
final long handle = 123456;
when(getServices().lockPatternUtils
- .addEscrowToken(eq(token), eq(DpmMockContext.CALLER_USER_HANDLE),
+ .addEscrowToken(eq(token), eq(CALLER_USER_HANDLE),
nullable(EscrowTokenStateChangeCallback.class)))
.thenReturn(handle);
dpm.setResetPasswordToken(admin1, token);
when(getServices().lockPatternUtils
- .isEscrowTokenActive(eq(handle), eq(DpmMockContext.CALLER_USER_HANDLE)))
+ .isEscrowTokenActive(eq(handle), eq(CALLER_USER_HANDLE)))
.thenReturn(true);
assertTrue("failed to activate token", dpm.isResetPasswordTokenActive(admin1));
@@ -6214,7 +6221,7 @@
doReturn(ai).when(getServices().ipackageManager).getApplicationInfo(
eq(admin1.getPackageName()),
anyInt(),
- eq(DpmMockContext.CALLER_USER_HANDLE));
+ eq(CALLER_USER_HANDLE));
}
private void setDeviceEncryptionPerUser() {
@@ -6302,7 +6309,8 @@
verifyZeroInteractions(getServices().ipackageManager);
clearInvocations(getServices().alarmManager);
- sendUserStoppedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, false);
+ sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Verify the alarm was scheduled for time when the warning should be shown.
verify(getServices().alarmManager, times(1))
@@ -6316,7 +6324,7 @@
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
- sendProfileOffDeadlineAlarmBroadcast();
+ sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
// Verify the alarm was scheduled for the actual deadline this time.
verify(getServices().alarmManager, times(1)).set(anyInt(), eq(PROFILE_OFF_DEADLINE), any());
@@ -6331,7 +6339,7 @@
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
- sendProfileOffDeadlineAlarmBroadcast();
+ sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
// Verify the alarm was not set.
verifyZeroInteractions(getServices().alarmManager);
@@ -6354,9 +6362,11 @@
dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- sendUserStoppedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, false);
+ sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
- sendUserUnlockedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, true);
+ sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the alarm got discharged.
verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6372,15 +6382,17 @@
dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- sendUserStoppedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, false);
+ sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
- sendProfileOffDeadlineAlarmBroadcast();
+ sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
clearInvocations(getServices().notificationManager);
- sendUserUnlockedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, true);
+ sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the alarm got discharged.
verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6399,17 +6411,25 @@
dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- sendUserStoppedBroadcastForProfile();
+ setUserUnlocked(CALLER_USER_HANDLE, false);
+ sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Pretend the alarm went off after the deadline.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
- sendProfileOffDeadlineAlarmBroadcast();
+ sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
clearInvocations(getServices().notificationManager);
clearInvocations(getServices().ipackageManager);
- sendUserUnlockedBroadcastForProfile();
+ // Pretend the user clicked on the "apps suspended" notification to turn the profile on.
+ sendBroadcastWithUser(ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
+ // Verify that the profile is turned on.
+ verify(getServices().userManager, times(1))
+ .requestQuietModeEnabled(eq(false), eq(UserHandle.of(CALLER_USER_HANDLE)));
+
+ setUserUnlocked(CALLER_USER_HANDLE, true);
+ sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the notification is removed (at this point DPC should show it).
verify(getServices().notificationManager, times(1))
@@ -6417,50 +6437,36 @@
// Verify that the apps are NOT unsuspeded.
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
any(), eq(false), any(), any(), any(), any(), anyInt());
+ // Verify that DPC is invoked to check policy compliance.
+ verify(mContext.spiedContext).startActivityAsUser(
+ MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
+ MockUtils.checkUserHandle(CALLER_USER_HANDLE));
}
- private void sendUserUnlockedBroadcastForProfile() throws Exception {
- when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
- .thenReturn(true);
- final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED)
- .putExtra(Intent.EXTRA_USER_HANDLE, DpmMockContext.CALLER_USER_HANDLE);
- getServices().injectBroadcast(
- mServiceContext, unlockedIntent, DpmMockContext.CALLER_USER_HANDLE);
+ private void sendBroadcastWithUser(String action, int userHandle) throws Exception {
+ final Intent intent = new Intent(action);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+ getServices().injectBroadcast(mServiceContext, intent, userHandle);
flushTasks();
}
-
- private void sendProfileOffDeadlineAlarmBroadcast() throws Exception {
- final Intent deadlineAlarmIntent =
- new Intent(DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE);
- getServices().injectBroadcast(
- mServiceContext, deadlineAlarmIntent, DpmMockContext.CALLER_USER_HANDLE);
- flushTasks();
- }
-
- private void sendUserStoppedBroadcastForProfile() throws Exception {
- when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
- .thenReturn(false);
- final Intent stoppedIntent = new Intent(Intent.ACTION_USER_STOPPED)
- .putExtra(Intent.EXTRA_USER_HANDLE, DpmMockContext.CALLER_USER_HANDLE);
- getServices().injectBroadcast(mServiceContext, stoppedIntent,
- DpmMockContext.CALLER_USER_HANDLE);
- flushTasks();
+ private void setUserUnlocked(int userHandle, boolean unlocked) {
+ when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
private void prepareMocksForSetMaximumProfileTimeOff() throws Exception {
addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
- configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
when(getServices().userManager.isUserUnlocked()).thenReturn(true);
// Pretend our admin handles CHECK_POLICY_COMPLIANCE intent.
- final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
+ final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
intent.setPackage(admin1.getPackageName());
doReturn(Collections.singletonList(new ResolveInfo()))
.when(getServices().packageManager).queryIntentActivitiesAsUser(
- any(Intent.class), anyInt(), eq(DpmMockContext.CALLER_USER_HANDLE));
+ any(Intent.class), anyInt(), eq(CALLER_USER_HANDLE));
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_START);
// To allow creation of Notification via Notification.Builder
@@ -6536,10 +6542,10 @@
// admin1 is the outgoing DPC, adminAnotherPackage is the incoming one.
private void assertProfileOwnershipRevertedWithFakeTransferMetadata() throws Exception {
- writeFakeTransferMetadataFile(DpmMockContext.CALLER_USER_HANDLE,
+ writeFakeTransferMetadataFile(CALLER_USER_HANDLE,
TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER);
- int uid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ int uid = UserHandle.getUid(CALLER_USER_HANDLE,
DpmMockContext.CALLER_SYSTEM_USER_UID);
setUpPackageManagerForAdmin(admin1, uid);
setUpPackageManagerForFakeAdmin(adminAnotherPackage, uid, admin1);
@@ -6550,7 +6556,7 @@
assertTrue(dpm.isAdminActive(admin1));
assertFalse(dpm.isProfileOwnerApp(adminAnotherPackage.getPackageName()));
assertFalse(dpm.isAdminActive(adminAnotherPackage));
- assertEquals(dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE), admin1);
+ assertEquals(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE), admin1);
assertFalse(getMockTransferMetadataManager().metadataFileExists());
}
@@ -6571,12 +6577,12 @@
}
private File getProfileOwnerFile() {
- return dpms.mOwners.getProfileOwnerFile(DpmMockContext.CALLER_USER_HANDLE);
+ return dpms.mOwners.getProfileOwnerFile(CALLER_USER_HANDLE);
}
private File getProfileOwnerPoliciesFile() {
File parentDir = dpms.mMockInjector.environmentGetUserSystemDirectory(
- DpmMockContext.CALLER_USER_HANDLE);
+ CALLER_USER_HANDLE);
return getPoliciesFile(parentDir);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 20716ab..ce7ac9e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -482,4 +482,9 @@
public int checkCallingPermission(String permission) {
return spiedContext.checkCallingPermission(permission);
}
+
+ @Override
+ public void startActivityAsUser(Intent intent, UserHandle userHandle) {
+ spiedContext.startActivityAsUser(intent, userHandle);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 08bd1ee..8137c36 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -16,7 +16,6 @@
package com.android.server.display;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
@@ -30,7 +29,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
-import com.android.server.display.DisplayModeDirector.RefreshRateRange;
import com.android.server.display.DisplayModeDirector.Vote;
import com.google.common.truth.Truth;
@@ -79,10 +77,12 @@
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/60,
- new RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
+ DesiredDisplayModeSpecs modeSpecs =
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
- displayId));
+ displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(60);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY);
int numPriorities =
DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
@@ -101,10 +101,12 @@
int priority = Vote.MIN_PRIORITY + i;
votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DesiredDisplayModeSpecs(
- /*baseModeId=*/minFps + i,
- new RefreshRateRange(minFps + i, maxFps - i)),
- director.getDesiredDisplayModeSpecs(displayId));
+ modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(minFps + i);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min)
+ .isEqualTo((float) (minFps + i));
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max)
+ .isEqualTo((float) (maxFps - i));
}
}
@@ -119,9 +121,10 @@
votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/70,
- new RefreshRateRange(70, 80)),
- director.getDesiredDisplayModeSpecs(displayId));
+ modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(70);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(70f);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(80f);
}
}
@@ -140,8 +143,8 @@
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
}
@@ -159,34 +162,77 @@
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
-
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ }
+ @Test
+ public void testAppRequestRefreshRateRange() {
+ // Confirm that the app request range doesn't include low brightness or min refresh rate
+ // settings, but does include everything else.
+ assertTrue(
+ Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
+ < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
+ >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ int displayId = 0;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(displayId, votes);
+ votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min)
+ .isWithin(FLOAT_TOLERANCE)
+ .of(75);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE)
+ .of(75);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 9c2ef4f..53c9bb2 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -116,7 +116,7 @@
// These are obtained by running the test and checking logcat.
private static final String APP_CERT =
- "C8A2E9BCCF597C2FB6DC66BEE293FC13F2FC47EC77BC6B2B0D52C11F51192AB8";
+ "F14CFECF5070874C05D3D2FA98E046BE20BDE02A0DC74BAF6B59C6A0E4C06850";
// We use SHA256 for package names longer than 32 characters.
private static final String INSTALLER_SHA256 =
"30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java
index c9dbdd2..acb20ed 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStrongAuthTest.java
@@ -24,6 +24,7 @@
import static com.android.server.locksettings.LockSettingsStrongAuth.NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG;
import static com.android.server.locksettings.LockSettingsStrongAuth.STRONG_AUTH_TIMEOUT_ALARM_TAG;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
@@ -163,9 +164,11 @@
@Test
public void testReportSuccessfulStrongAuthUnlock_schedulePrimaryAuthTimeout() {
- final long nextAlarmTime = 1000;
- when(mInjector.getNextAlarmTimeMs(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)))
- .thenReturn(nextAlarmTime);
+ final long currentTime = 1000;
+ final long timeout = 1000;
+ final long nextAlarmTime = currentTime + timeout;
+ when(mInjector.getElapsedRealtimeMs()).thenReturn(currentTime);
+ when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(timeout);
mStrongAuth.reportSuccessfulStrongAuthUnlock(PRIMARY_USER_ID);
waitForIdle();
@@ -178,6 +181,29 @@
}
@Test
+ public void testReportSuccessfulStrongAuthUnlock_testRefreshStrongAuthTimeout() {
+ final long currentTime = 1000;
+ final long oldTimeout = 5000;
+ final long nextAlarmTime = currentTime + oldTimeout;
+ when(mInjector.getElapsedRealtimeMs()).thenReturn(currentTime);
+ when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(oldTimeout);
+ mStrongAuth.reportSuccessfulStrongAuthUnlock(PRIMARY_USER_ID);
+ waitForIdle();
+
+ StrongAuthTimeoutAlarmListener alarm =
+ mStrongAuth.mStrongAuthTimeoutAlarmListenerForUser.get(PRIMARY_USER_ID);
+ assertEquals(currentTime, alarm.getLatestStrongAuthTime());
+ verifyAlarm(nextAlarmTime, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm);
+
+ final long newTimeout = 3000;
+ when(mDPM.getRequiredStrongAuthTimeout(null, PRIMARY_USER_ID)).thenReturn(newTimeout);
+ mStrongAuth.refreshStrongAuthTimeout(PRIMARY_USER_ID);
+ waitForIdle();
+ verify(mAlarmManager).cancel(alarm);
+ verifyAlarm(currentTime + newTimeout, STRONG_AUTH_TIMEOUT_ALARM_TAG, alarm);
+ }
+
+ @Test
public void testReportSuccessfulStrongAuthUnlock_cancelAlarmsAndAllowNonStrongBio() {
setupAlarms(PRIMARY_USER_ID);
mStrongAuth.reportSuccessfulStrongAuthUnlock(PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index ea8aa6b..70d6cf8 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -54,7 +54,6 @@
.setPersonImportant(true)
.setPersonBot(true)
.setContactStarred(true)
- .setNotificationSettingChanged(true)
.build();
assertEquals(SHORTCUT_ID, conversationInfo.getShortcutId());
@@ -71,7 +70,6 @@
assertTrue(conversationInfo.isPersonImportant());
assertTrue(conversationInfo.isPersonBot());
assertTrue(conversationInfo.isContactStarred());
- assertTrue(conversationInfo.isNotificationSettingChanged());
}
@Test
@@ -94,7 +92,6 @@
assertFalse(conversationInfo.isPersonImportant());
assertFalse(conversationInfo.isPersonBot());
assertFalse(conversationInfo.isContactStarred());
- assertFalse(conversationInfo.isNotificationSettingChanged());
}
@Test
@@ -112,7 +109,6 @@
.setPersonImportant(true)
.setPersonBot(true)
.setContactStarred(true)
- .setNotificationSettingChanged(true)
.build();
ConversationInfo destination = new ConversationInfo.Builder(source)
@@ -132,6 +128,5 @@
assertTrue(destination.isPersonImportant());
assertTrue(destination.isPersonBot());
assertFalse(destination.isContactStarred());
- assertTrue(destination.isNotificationSettingChanged());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index e51ab9db..1a2032a 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -49,6 +49,7 @@
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -95,8 +96,6 @@
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -125,18 +124,19 @@
@Mock private TelephonyManager mTelephonyManager;
@Mock private TelecomManager mTelecomManager;
@Mock private ContentResolver mContentResolver;
- @Mock private ScheduledExecutorService mExecutorService;
@Mock private JobScheduler mJobScheduler;
- @Mock private ScheduledFuture mScheduledFuture;
@Mock private StatusBarNotification mStatusBarNotification;
@Mock private Notification mNotification;
@Captor private ArgumentCaptor<ShortcutChangeCallback> mShortcutChangeCallbackCaptor;
+ @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ private ScheduledExecutorService mExecutorService;
private NotificationChannel mNotificationChannel;
private DataManager mDataManager;
private CancellationSignal mCancellationSignal;
private ShortcutChangeCallback mShortcutChangeCallback;
+ private BroadcastReceiver mShutdownBroadcastReceiver;
private TestInjector mInjector;
@Before
@@ -182,13 +182,7 @@
when(mContext.getSystemServiceName(JobScheduler.class)).thenReturn(
Context.JOB_SCHEDULER_SERVICE);
- when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(
- TimeUnit.class))).thenReturn(mScheduledFuture);
- doAnswer(ans -> {
- Runnable runnable = (Runnable) ans.getArguments()[0];
- runnable.run();
- return null;
- }).when(mExecutorService).execute(any(Runnable.class));
+ mExecutorService = new MockScheduledExecutorService();
when(mUserManager.getEnabledProfiles(USER_ID_PRIMARY))
.thenReturn(Arrays.asList(
@@ -221,6 +215,9 @@
verify(mShortcutServiceInternal).addShortcutChangeCallback(
mShortcutChangeCallbackCaptor.capture());
mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+ mShutdownBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
}
@After
@@ -459,7 +456,7 @@
}
@Test
- public void testShortcutNotUncachedIfSettingChanged() {
+ public void testShortcutNotUncachedIfNotificationChannelCreated() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
@@ -473,7 +470,6 @@
shortcut.setCached();
mDataManager.addOrUpdateConversationInfo(shortcut);
- mNotificationChannel.setImportantConversation(true);
listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
@@ -530,7 +526,6 @@
assertTrue(conversationInfo.isImportant());
assertFalse(conversationInfo.isNotificationSilenced());
assertFalse(conversationInfo.isDemoted());
- assertTrue(conversationInfo.isNotificationSettingChanged());
}
@Test
@@ -563,6 +558,51 @@
}
@Test
+ public void testUncacheShortcutWhenShutdown() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ shortcut.setCached();
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ }
+
+ @Test
+ public void testDoNotUncacheShortcutWhenShutdownIfNotificationChannelCreated() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ shortcut.setCached();
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ }
+
+ @Test
public void testShortcutAddedOrUpdated() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
@@ -722,6 +762,22 @@
}
@Test
+ public void testPruneInactiveCachedShortcuts() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached();
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
+
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY));
+ }
+
+ @Test
public void testBackupAndRestoration()
throws IntentFilter.MalformedMimeTypeException {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
index aecbc8d..8cb846f 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
@@ -96,7 +96,6 @@
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
TimeUnit unit) {
- Preconditions.checkState(unit == TimeUnit.MILLISECONDS);
return new MockScheduledFuture<>(command, period, unit);
}
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index 1480627..c271639 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -16,8 +16,6 @@
package com.android.server.people.prediction;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -274,8 +272,20 @@
mUpdatePredictionsMethod);
verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
- assertThat(mAppTargetCaptor.getValue()).containsExactly(
- appTarget4, appTarget3, appTarget2, appTarget1, appTarget5);
+ List<AppTarget> res = mAppTargetCaptor.getValue();
+ assertEquals(5, res.size());
+ checkAppTarget(appTarget4, res.get(0));
+ checkAppTarget(appTarget3, res.get(1));
+ checkAppTarget(appTarget2, res.get(2));
+ checkAppTarget(appTarget1, res.get(3));
+ checkAppTarget(appTarget5, res.get(4));
+ }
+
+ private static void checkAppTarget(AppTarget expected, AppTarget actual) {
+ assertEquals(expected.getId(), actual.getId());
+ assertEquals(expected.getClassName(), actual.getClassName());
+ assertEquals(expected.getPackageName(), actual.getPackageName());
+ assertEquals(expected.getUser(), actual.getUser());
}
private static ShareShortcutInfo buildShareShortcut(
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
index 9d96d6b..9fc1776 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
@@ -281,9 +281,9 @@
verify(mDataManager, times(1)).queryAppLaunchCount(anyInt(), anyLong(), anyLong(),
anySet());
- assertEquals(0.9f, mShareTarget5.getScore(), DELTA);
- assertEquals(0.81f, mShareTarget3.getScore(), DELTA);
- assertEquals(0.729f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0.3f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0.27f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0.243f, mShareTarget1.getScore(), DELTA);
assertEquals(0f, mShareTarget2.getScore(), DELTA);
assertEquals(0f, mShareTarget4.getScore(), DELTA);
assertEquals(0f, mShareTarget6.getScore(), DELTA);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index d4edab4..63d797e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -178,6 +178,7 @@
/* files */ null,
/* prepared */ true,
/* committed */ true,
+ /* destroyed */ staged ? true : false,
/* sealed */ false, // Setting to true would trigger some PM logic.
/* childSessionIds */ childSessionIds != null ? childSessionIds : new int[0],
/* parentSessionId */ parentSessionId,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 0a68688..37c1060 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -53,7 +53,7 @@
public void sendPackageAddedForNewUsers(String packageName,
boolean sendBootComplete, boolean includeStopped, int appId,
- int[] userIds, int[] instantUserIds) {
+ int[] userIds, int[] instantUserIds, int dataLoaderType) {
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index daaf870..b0b5386 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -154,18 +154,7 @@
@Test
public void test_serializePackage() throws Exception {
- try (PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir,
- new PackageParser2.Callback() {
- @Override
- public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
- return true;
- }
-
- @Override
- public boolean hasFeature(String feature) {
- return false;
- }
- })) {
+ try (PackageParser2 pp = PackageParser2.forParsingFileWithDefaults()) {
ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
true /* useCaches */);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index bec37e9..6b3ee5a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -802,6 +802,7 @@
@Test
public void testCreateProfile_withContextUserId() throws Exception {
+ assumeManagedUsersSupported();
final int primaryUserId = mUserManager.getPrimaryUser().id;
UserInfo userProfile = createProfileForUser("Managed 1",
@@ -820,6 +821,7 @@
@Test
public void testSetUserName_withContextUserId() throws Exception {
+ assumeManagedUsersSupported();
final int primaryUserId = mUserManager.getPrimaryUser().id;
UserInfo userInfo1 = createProfileForUser("Managed 1",
@@ -855,6 +857,7 @@
@Test
public void testGetUserIcon_withContextUserId() throws Exception {
+ assumeManagedUsersSupported();
final int primaryUserId = mUserManager.getPrimaryUser().id;
UserInfo userInfo1 = createProfileForUser("Managed 1",
@@ -975,8 +978,11 @@
}
private void assumeManagedUsersSupported() {
+ // In Automotive, if headless system user is enabled, a managed user cannot be created
+ // under a primary user.
assumeTrue("device doesn't support managed users",
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS));
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)
+ && (!isAutomotive() || !UserManager.isHeadlessSystemUserMode()));
}
private boolean isAutomotive() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 3888ff3..caa8ae5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -28,8 +28,13 @@
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.FileUtils;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -208,9 +213,12 @@
throws IOException, PackageParserException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
File dm = createDexMetadataFile("install_split_base.apk");
- PackageParser.PackageLite pkg = new PackageParser().parsePackageLite(mTmpDir,
- 0 /* flags */);
-
+ ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+ ParseTypeImpl.forDefaultParsing().reset(), mTmpDir, 0 /* flags */);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+ PackageParser.PackageLite pkg = result.getResult();
Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkg));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 7b1b2d2..086c845 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -23,16 +23,15 @@
import android.content.pm.FeatureInfo
import android.content.pm.InstrumentationInfo
import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
import android.content.pm.PackageParser
import android.content.pm.PackageUserState
import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
import android.os.Debug
import android.os.Environment
-import android.os.ServiceManager
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.compat.IPlatformCompat
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -62,27 +61,7 @@
setCallback { false /* hasFeature */ }
}
- private val platformCompat = IPlatformCompat.Stub
- .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE))
-
- protected val packageParser2 = PackageParser2(null /* separateProcesses */,
- false /* onlyCoreApps */, context.resources.displayMetrics, null /* cacheDir */,
- object : PackageParser2.Callback() {
- override fun isChangeEnabled(
- changeId: Long,
- appInfo: ApplicationInfo
- ): Boolean {
- // This test queries PlatformCompat because prebuilts in the tree
- // may not be updated to be compliant with the latest enforcement checks.
- return platformCompat.isChangeEnabled(changeId, appInfo)
- }
-
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature permissions.
- // This mirrors the old behavior.
- override fun hasFeature(feature: String) = false
- })
+ protected val packageParser2 = PackageParser2.forParsingFileWithDefaults()
/**
* It would be difficult to mock all possibilities, so just use the APKs on device.
@@ -168,6 +147,11 @@
private fun <T> tryOrNull(block: () -> T) = try {
block()
+ } catch (e: PackageParser.PackageParserException) {
+ if (e.error != PackageManager.INSTALL_PARSE_FAILED_SKIPPED) {
+ thrownInSetUp.add(e)
+ }
+ null
} catch (t: Throwable) {
thrownInSetUp.add(t)
null
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 939b7a0..bb223b3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -29,8 +29,12 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedComponent;
import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.result.ParseResult;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -518,10 +522,15 @@
apexInfo.versionCode = 191000070;
int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
- PackageParser pp = new PackageParser();
- PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
- PackageParser.collectCertificates(p, false);
- PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
+ ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefaultOneTime(apexFile,
+ flags, false /*collectCertificates*/);
+ if (result.isError()) {
+ throw new IllegalStateException(result.getErrorMessage(), result.getException());
+ }
+
+ ParsingPackage pkg = result.getResult();
+ pkg.setSigningDetails(ParsingPackageUtils.getSigningDetails(pkg, false));
+ PackageInfo pi = PackageInfoWithoutStateUtils.generate(pkg, apexInfo, flags);
assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
assertTrue(pi.applicationInfo.enabled);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 2248707..d8910de 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -64,20 +64,6 @@
}
}
- private val parsingCallback = object : ParsingPackageUtils.Callback {
- override fun hasFeature(feature: String?) = true
-
- override fun startParsingPackage(
- packageName: String,
- baseCodePath: String,
- codePath: String,
- manifestArray: TypedArray,
- isCoreApp: Boolean
- ): ParsingPackage {
- return ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
- }
- }
-
@get:Rule
val tempFolder = TemporaryFolder(context.filesDir)
@@ -144,6 +130,7 @@
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0, inputCallback, parsingCallback)
+ return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/,
+ false /*collectCertificates*/)
}
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 21af356..f934323 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -64,6 +64,7 @@
private Context mContextSpy;
@Mock private ITvInputManager mITvInputManagerMock;
private TunerResourceManagerService mTunerResourceManagerService;
+ private boolean mIsForeground;
private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub {
boolean mReclaimed;
@@ -104,7 +105,12 @@
TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
- mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy);
+ mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {
+ @Override
+ protected boolean isForeground(int pid) {
+ return mIsForeground;
+ }
+ };
mTunerResourceManagerService.onStart(true /*isForTesting*/);
}
@@ -737,4 +743,22 @@
.isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(desHandle[0])).isEqualTo(0);
}
+
+ @Test
+ public void isHigherPriorityTest() {
+ mIsForeground = false;
+ ResourceClientProfile backgroundPlaybackProfile =
+ new ResourceClientProfile(null /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ ResourceClientProfile backgroundRecordProfile =
+ new ResourceClientProfile(null /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
+ int backgroundPlaybackPriority = mTunerResourceManagerService.getClientPriority(
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 0);
+ int backgroundRecordPriority = mTunerResourceManagerService.getClientPriority(
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 0);
+ assertThat(mTunerResourceManagerService.isHigherPriorityInternal(backgroundPlaybackProfile,
+ backgroundRecordProfile)).isEqualTo(
+ (backgroundPlaybackPriority > backgroundRecordPriority));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e548647..e86399e 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -70,8 +70,12 @@
mLocalService = mService.getLocalService();
}
+ /**
+ * Verify that a camera sharing a normally-private photo with a social media
+ * app in the same user issues a grant.
+ */
@Test
- public void testNeeded_normal() {
+ public void testNeeded_normal_sameUser() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
@@ -85,6 +89,24 @@
}
/**
+ * Verify that a camera sharing a normally-private photo with a social media
+ * app in a different user issues a grant.
+ */
+ @Test
+ public void testNeeded_normal_differentUser() {
+ final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
+ final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
+
+ final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
+ UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
+ USER_SECONDARY);
+ assertEquals(PKG_SOCIAL, needed.targetPkg);
+ assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
+ assertEquals(FLAG_READ, needed.flags);
+ assertEquals(asSet(expectedGrant), needed.uris);
+ }
+
+ /**
* No need to issue grants for public authorities.
*/
@Test
@@ -149,7 +171,7 @@
final Uri uri = Uri.parse("content://" + PKG_COMPLEX + "/");
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
- .addFlags(FLAG_READ);
+ .addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
assertNull(mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
intent, intent.getFlags(), null, USER_PRIMARY));
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 39062f0..48e22f6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -165,6 +165,7 @@
long mElapsedRealtime;
boolean mIsAppIdleEnabled = true;
boolean mIsCharging;
+ boolean mIsRestrictedBucketEnabled = true;
List<String> mNonIdleWhitelistApps = new ArrayList<>();
boolean mDisplayOn;
DisplayManager.DisplayListener mDisplayListener;
@@ -212,6 +213,11 @@
}
@Override
+ boolean isRestrictedBucketEnabled() {
+ return mIsRestrictedBucketEnabled;
+ }
+
+ @Override
File getDataSystemDirectory() {
return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
}
@@ -366,29 +372,87 @@
mInjector.mElapsedRealtime, false));
}
+ private static class TestParoleListener extends AppIdleStateChangeListener {
+ private boolean mIsParoleOn = false;
+ private CountDownLatch mLatch;
+ private boolean mIsExpecting = false;
+ private boolean mExpectedParoleState;
+
+ boolean getParoleState() {
+ synchronized (this) {
+ return mIsParoleOn;
+ }
+ }
+
+ void rearmLatch(boolean expectedParoleState) {
+ synchronized (this) {
+ mLatch = new CountDownLatch(1);
+ mIsExpecting = true;
+ mExpectedParoleState = expectedParoleState;
+ }
+ }
+
+ void awaitOnLatch(long time) throws Exception {
+ mLatch.await(time, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+ int bucket, int reason) {
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ synchronized (this) {
+ // Only record information if it is being looked for
+ if (mLatch != null && mLatch.getCount() > 0) {
+ mIsParoleOn = isParoleOn;
+ if (mIsExpecting && isParoleOn == mExpectedParoleState) {
+ mLatch.countDown();
+ }
+ }
+ }
+ }
+ }
+
@Test
public void testIsAppIdle_Charging() throws Exception {
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+
setChargingState(mController, false);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
REASON_MAIN_FORCED_BY_SYSTEM);
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertFalse(mController.isInParole());
+ paroleListener.rearmLatch(true);
setChargingState(mController, true);
+ paroleListener.awaitOnLatch(2000);
+ assertTrue(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertTrue(mController.isInParole());
+ paroleListener.rearmLatch(false);
setChargingState(mController, false);
+ paroleListener.awaitOnLatch(2000);
+ assertFalse(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ assertFalse(mController.isInParole());
}
@Test
public void testIsAppIdle_Enabled() throws Exception {
setChargingState(mController, false);
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+
setAppIdleEnabled(mController, true);
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
REASON_MAIN_FORCED_BY_SYSTEM);
@@ -396,11 +460,17 @@
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ paroleListener.rearmLatch(false);
setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(2000);
+ assertTrue(paroleListener.mIsParoleOn);
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+ paroleListener.rearmLatch(true);
setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(2000);
+ assertFalse(paroleListener.getParoleState());
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
@@ -447,6 +517,10 @@
assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
}
+ private void assertNotBucket(int bucket) {
+ assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+ }
+
@Test
public void testBuckets() throws Exception {
assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
@@ -882,6 +956,48 @@
}
@Test
+ public void testRestrictedBucketDisabled() {
+ mInjector.mIsRestrictedBucketEnabled = false;
+ // Get the controller to read the new value. Capturing the ContentObserver isn't possible
+ // at the moment.
+ mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+
+ // Nothing should be able to put it into the RESTRICTED bucket.
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_TIMEOUT);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_PREDICTED);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_USER);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ }
+
+ @Test
+ public void testRestrictedBucket_EnabledToDisabled() {
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
+ REASON_MAIN_FORCED_BY_SYSTEM);
+ assertBucket(STANDBY_BUCKET_RESTRICTED);
+
+ mInjector.mIsRestrictedBucketEnabled = false;
+ // Get the controller to read the new value. Capturing the ContentObserver isn't possible
+ // at the moment.
+ mController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mController.checkIdleStates(USER_ID);
+ assertNotBucket(STANDBY_BUCKET_RESTRICTED);
+ }
+
+ @Test
public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index f1c3906..60390dc 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -126,7 +126,7 @@
mIntervalStats.majorVersion = 7;
mIntervalStats.minorVersion = 8;
- mIntervalStats.beginTime = time;
+ mIntervalStats.beginTime = time - 1;
mIntervalStats.interactiveTracker.count = 2;
mIntervalStats.interactiveTracker.duration = 111111;
mIntervalStats.nonInteractiveTracker.count = 3;
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index 3c2d550..182bf94 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -41,6 +41,7 @@
protected static final String PKG_N_MR1 = "com.example.n_mr1";
protected static final String PKG_O = "com.example.o";
protected static final String PKG_P = "com.example.p";
+ protected static final String PKG_R = "com.example.r";
@Rule
public final TestableContext mContext =
@@ -69,6 +70,8 @@
return Build.VERSION_CODES.O;
case PKG_P:
return Build.VERSION_CODES.P;
+ case PKG_R:
+ return Build.VERSION_CODES.R;
default:
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
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 d5ecfeb..289933e 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -250,6 +250,8 @@
private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
+ private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
+
@Mock
private NotificationListeners mListeners;
@Mock private NotificationAssistants mAssistants;
@@ -471,6 +473,19 @@
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
+ // Pretend the shortcut exists
+ List<ShortcutInfo> shortcutInfos = new ArrayList<>();
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getPackage()).thenReturn(PKG);
+ when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
+ when(info.getUserId()).thenReturn(USER_SYSTEM);
+ when(info.isLongLived()).thenReturn(true);
+ when(info.isEnabled()).thenReturn(true);
+ shortcutInfos.add(info);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
+ when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
+ anyString(), anyInt(), any())).thenReturn(true);
+
// Set the testable bubble extractor
RankingHelper rankingHelper = mService.getRankingHelper();
BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
@@ -704,6 +719,7 @@
)
.setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setShortcutId(VALID_CONVO_SHORTCUT_ID)
.setGroupSummary(isSummary);
if (groupKey != null) {
nb.setGroup(groupKey);
@@ -1772,6 +1788,28 @@
}
@Test
+ public void testGroupInstanceIds() throws Exception {
+ final NotificationRecord group1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group1", true);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked",
+ group1.getSbn().getId(), group1.getSbn().getNotification(),
+ group1.getSbn().getUserId());
+ waitForIdle();
+
+ // same group, child, should be returned
+ final NotificationRecord group1Child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group1", false);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked",
+ group1Child.getSbn().getId(),
+ group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId());
+ waitForIdle();
+
+ assertEquals(2, mNotificationRecordLogger.numCalls());
+ assertEquals(mNotificationRecordLogger.get(0).getInstanceId(),
+ mNotificationRecordLogger.get(1).groupInstanceId.getId());
+ }
+
+ @Test
public void testFindGroupNotificationsLocked() throws Exception {
// make sure the same notification can be found in both lists and returned
final NotificationRecord group1 = generateNotificationRecord(
@@ -4910,7 +4948,32 @@
eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
- assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED,
+ assertEquals(
+ NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2,
+ mNotificationRecordLogger.event(0));
+ }
+
+ @Test
+ public void testOnAssistantNotificationActionClick() {
+ final int actionIndex = 1;
+ final Notification.Action action =
+ new Notification.Action.Builder(null, "text", null).build();
+ final boolean generatedByAssistant = true;
+
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+
+ NotificationVisibility notificationVisibility =
+ NotificationVisibility.obtain(r.getKey(), 1, 2, true);
+ mService.mNotificationDelegate.onNotificationActionClick(
+ 10, 10, r.getKey(), actionIndex, action, notificationVisibility,
+ generatedByAssistant);
+ verify(mAssistants).notifyAssistantActionClicked(
+ eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+
+ assertEquals(1, mNotificationRecordLogger.numCalls());
+ assertEquals(
+ NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1,
mNotificationRecordLogger.event(0));
}
@@ -6053,7 +6116,6 @@
@Test
public void testNotificationBubbles_flagRemoved_whenShortcutRemoved()
throws RemoteException {
- final String shortcutId = "someshortcutId";
setUpPrefsForBubbles(PKG, mUid,
true /* global */,
BUBBLE_PREFERENCE_ALL /* app */,
@@ -6064,27 +6126,16 @@
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder(shortcutId).build();
+ new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build();
Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
null /* groupKey */, false /* isSummary */);
- nb.setShortcutId(shortcutId);
+ nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
nb.setBubbleMetadata(metadata);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- // Pretend the shortcut exists
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(PKG);
- when(info.getId()).thenReturn(shortcutId);
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
- when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
- anyString(), anyInt(), any())).thenReturn(true);
+
// Test: Send the bubble notification
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
@@ -6102,7 +6153,7 @@
// Make sure the shortcut is cached.
verify(mShortcutServiceInternal).cacheShortcuts(
- anyInt(), any(), eq(PKG), eq(Collections.singletonList(shortcutId)),
+ anyInt(), any(), eq(PKG), eq(Collections.singletonList(VALID_CONVO_SHORTCUT_ID)),
eq(USER_SYSTEM));
// Test: Remove the shortcut
@@ -6566,6 +6617,7 @@
convo2.setNotificationChannel(channel2);
convos.add(convo2);
when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
List<ConversationChannelWrapper> conversations =
mBinderService.getConversationsForPackage(PKG_P, mUid).getList();
@@ -6593,6 +6645,7 @@
NotificationRecord nr =
generateMessageBubbleNotifRecord(mTestNotificationChannel,
"testRecordMessages_invalidMsg");
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
@@ -6613,21 +6666,68 @@
"testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- // Pretend the shortcut exists
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(PKG);
- when(info.getId()).thenReturn("id");
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
-
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
assertFalse(mBinderService.hasSentMessage(PKG, mUid));
}
+
+ @Test
+ public void testCanPostFgsWhenOverLimit() throws RemoteException {
+ for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+ StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
+ i, null, false).getSbn();
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testCanPostFgsWhenOverLimit",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ }
+
+ final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testCanPostFgsWhenOverLimit - fgs over limit!",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+
+ waitForIdle();
+
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(sbn.getPackageName());
+ assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
+ assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
+ mService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testCannotPostNonFgsWhenOverLimit() throws RemoteException {
+ for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+ StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
+ i, null, false).getSbn();
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testCanPostFgsWhenOverLimit",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ }
+
+ final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
+ 100, null, false).getSbn();
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testCanPostFgsWhenOverLimit - fgs over limit!",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+
+ final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel,
+ 101, null, false).getSbn();
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testCanPostFgsWhenOverLimit - non fgs over limit!",
+ sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
+
+ waitForIdle();
+
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(sbn.getPackageName());
+ assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length);
+ assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
+ mService.getNotificationRecordCount());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
index 6b18cc6..64fd19e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import java.util.ArrayList;
@@ -32,14 +33,16 @@
static final int INVALID = -1;
public int position = INVALID, buzzBeepBlink = INVALID;
public boolean wasLogged;
+ public InstanceId groupInstanceId;
CallRecord(NotificationRecord r, NotificationRecord old, int position,
- int buzzBeepBlink) {
+ int buzzBeepBlink, InstanceId groupId) {
super(r, old);
this.position = position;
this.buzzBeepBlink = buzzBeepBlink;
wasLogged = shouldLogReported(buzzBeepBlink);
event = wasLogged ? NotificationReportedEvent.fromRecordPair(this) : null;
+ groupInstanceId = groupId;
}
CallRecord(NotificationRecord r, UiEventLogger.UiEventEnum event) {
@@ -67,8 +70,8 @@
@Override
public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old,
- int position, int buzzBeepBlink) {
- mCalls.add(new CallRecord(r, old, position, buzzBeepBlink));
+ int position, int buzzBeepBlink, InstanceId groupId) {
+ mCalls.add(new CallRecord(r, old, position, buzzBeepBlink, groupId));
}
@Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 9f593ce..b03596a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -39,7 +39,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.Notification;
@@ -90,7 +89,7 @@
@Mock private PackageManager mPm;
@Mock private ContentResolver mContentResolver;
- private final String pkg = PKG_N_MR1;
+ private final String mPkg = PKG_O;
private final int uid = 9583;
private final int id1 = 1;
private final String tag1 = "tag1";
@@ -198,10 +197,14 @@
}
Notification n = builder.build();
- return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
+ return new StatusBarNotification(mPkg, mPkg, id1, tag1, uid, uid, n, mUser, null, uid);
}
private StatusBarNotification getMessagingStyleNotification() {
+ return getMessagingStyleNotification(mPkg);
+ }
+
+ private StatusBarNotification getMessagingStyleNotification(String pkg) {
final Builder builder = new Builder(mMockContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon);
@@ -658,7 +661,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
@@ -687,7 +690,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
assertEquals(USER_SENTIMENT_POSITIVE, record.getUserSentiment());
@@ -705,7 +708,7 @@
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
- record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+ record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
record.applyAdjustments();
@@ -1134,6 +1137,15 @@
}
@Test
+ public void testIsConversation_noShortcut_targetsR() {
+ StatusBarNotification sbn = getMessagingStyleNotification(PKG_R);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+ record.setShortcutInfo(null);
+
+ assertFalse(record.isConversation());
+ }
+
+ @Test
public void testIsConversation_channelDemoted() {
StatusBarNotification sbn = getMessagingStyleNotification();
channel.setDemoted(true);
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 6cb8b86..e2821f4 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -25,6 +25,7 @@
"testables",
"ub-uiautomator",
"hamcrest-library",
+ "compatibility-device-util-axt",
],
libs: [
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 123bb07..fdc9401 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -54,8 +54,12 @@
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityViewTestActivity" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityInActivityView"
android:resizeableActivity="true" />
+ <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$LandscapeActivity"
+ android:screenOrientation="sensorLandscape"
+ android:showWhenLocked="true"
+ android:turnScreenOn="true" />
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
- android:showWhenLocked="true" />
+ android:showWhenLocked="true" android:allowEmbedded="true"/>
</application>
<instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 5227f3c..822cb5a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -66,6 +66,7 @@
import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
+import android.os.Binder;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -1291,6 +1292,27 @@
}
@Test
+ public void testShouldUpRecreateTaskLockedWithCorrectAffinityFormat() {
+ final String affinity = "affinity";
+ final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+ .setUid(Binder.getCallingUid()).setCreateTask(true).build();
+ activity.getTask().affinity = activity.taskAffinity;
+
+ assertFalse(mStack.shouldUpRecreateTaskLocked(activity, affinity));
+ }
+
+ @Test
+ public void testShouldUpRecreateTaskLockedWithWrongAffinityFormat() {
+ final String affinity = "affinity";
+ final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+ .setUid(Binder.getCallingUid()).setCreateTask(true).build();
+ activity.getTask().affinity = activity.taskAffinity;
+ final String fakeAffinity = activity.getUid() + activity.taskAffinity;
+
+ assertTrue(mStack.shouldUpRecreateTaskLocked(activity, fakeAffinity));
+ }
+
+ @Test
public void testResetTaskWithFinishingActivities() {
final ActivityRecord taskTop =
new ActivityBuilder(mService).setStack(mStack).setCreateTask(true).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 2991859..466f1a9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -109,6 +109,7 @@
private String mTargetActivity;
private Task mTask;
private String mProcessName = "name";
+ private String mAffinity;
private int mUid = 12345;
private boolean mCreateTask;
private ActivityStack mStack;
@@ -223,6 +224,11 @@
return this;
}
+ ActivityBuilder setAffinity(String affinity) {
+ mAffinity = affinity;
+ return this;
+ }
+
ActivityRecord build() {
try {
mService.deferWindowLayout();
@@ -271,6 +277,7 @@
aInfo.maxAspectRatio = mMaxAspectRatio;
aInfo.screenOrientation = mScreenOrientation;
aInfo.configChanges |= mConfigChanges;
+ aInfo.taskAffinity = mAffinity;
ActivityOptions options = null;
if (mLaunchTaskBehind) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index cf3cfec..5c21853 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -31,10 +31,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -59,6 +61,8 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -365,6 +369,30 @@
assertHasStartingWindow(activity2);
}
+ @Test
+ public void testTransferStartingWindowCanAnimate() {
+ final ActivityRecord activity1 = createIsolatedTestActivityRecord();
+ final ActivityRecord activity2 = createIsolatedTestActivityRecord();
+ activity1.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false, false);
+ waitUntilHandlersIdle();
+ activity2.addStartingWindow(mPackageName,
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+ true, true, false, true, false, false);
+ waitUntilHandlersIdle();
+ assertNoStartingWindow(activity1);
+ assertHasStartingWindow(activity2);
+
+ // Assert that bottom activity is allowed to do animation.
+ doReturn(true).when(activity2).okToAnimate();
+ doReturn(true).when(activity2).isAnimating();
+ final OnAnimationFinishedCallback onAnimationFinishedCallback =
+ mock(OnAnimationFinishedCallback.class);
+ assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false,
+ onAnimationFinishedCallback));
+ }
+
private ActivityRecord createIsolatedTestActivityRecord() {
final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(taskStack, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index cba89d0..ac95a81 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,7 +57,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -1068,13 +1067,6 @@
mDisplayContent.computeScreenConfiguration(config);
mDisplayContent.onRequestedOverrideConfigurationChanged(config);
- final ActivityRecord closingApp = new ActivityTestsBase.StackBuilder(mWm.mRoot)
- .setDisplay(mDisplayContent).setOnTop(false).build().getTopMostActivity();
- closingApp.nowVisible = true;
- closingApp.startAnimation(closingApp.getPendingTransaction(), mock(AnimationAdapter.class),
- false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
- assertTrue(closingApp.isAnimating());
-
final ActivityRecord app = mAppWindow.mActivityRecord;
mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */);
@@ -1135,8 +1127,6 @@
// The display should be rotated after the launch is finished.
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
- // The animation in old rotation should be cancelled.
- assertFalse(closingApp.isAnimating());
// The fixed rotation should be cleared and the new rotation is applied to display.
assertFalse(app.hasFixedRotationTransform());
assertFalse(app2.hasFixedRotationTransform());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 28ae36a..d605ab2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -38,13 +38,11 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -346,82 +344,6 @@
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appDrawsBarsLegacy() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
- }
-
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appWontDrawBars() {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
- }
-
- // TODO(b/118118435): remove after migration
- @Test
- public void layoutWindowLw_appWontDrawBars_forceStatusAndNav() throws Exception {
- assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
-
- mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
- mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- }
-
- // TODO(b/118118435): remove after migration (keyguard dialog is not special with the new logic)
- @Test
- public void layoutWindowLw_keyguardDialog_hideNav() {
- mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
- }
-
@Test
public void layoutWindowLw_withDisplayCutout() {
addDisplayCutout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index d0fd50d..c2db0c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,9 +16,12 @@
package com.android.server.wm;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -29,29 +32,33 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.InsetsState;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -307,4 +314,42 @@
win.mHasSurface = true;
return win;
}
+
+ @Test
+ public void testUpdateHideNavInputEventReceiver() {
+ final InsetsPolicy insetsPolicy = mDisplayContent.getInsetsPolicy();
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+ displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
+ displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
+ displayPolicy.addWindowLw(mNotificationShadeWindow, mNotificationShadeWindow.mAttrs);
+ spyOn(displayPolicy);
+ doReturn(true).when(displayPolicy).hasNavigationBar();
+
+ // App doesn't request to hide navigation bar.
+ insetsPolicy.updateBarControlTarget(mAppWindow);
+ assertNull(displayPolicy.mInputConsumer);
+
+ // App requests to hide navigation bar.
+ final InsetsState requestedState = new InsetsState();
+ requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+ mAppWindow.updateRequestedInsetsState(requestedState);
+ insetsPolicy.onInsetsModified(mAppWindow, requestedState);
+ assertNotNull(displayPolicy.mInputConsumer);
+
+ // App still requests to hide navigation bar, but without BEHAVIOR_SHOW_BARS_BY_TOUCH.
+ mAppWindow.mAttrs.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
+ insetsPolicy.updateBarControlTarget(mAppWindow);
+ assertNull(displayPolicy.mInputConsumer);
+
+ // App still requests to hide navigation bar, but with BEHAVIOR_SHOW_BARS_BY_TOUCH.
+ mAppWindow.mAttrs.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
+ insetsPolicy.updateBarControlTarget(mAppWindow);
+ assertNotNull(displayPolicy.mInputConsumer);
+
+ // App still requests to hide navigation bar with BEHAVIOR_SHOW_BARS_BY_TOUCH,
+ // but notification shade forcibly shows navigation bar
+ mNotificationShadeWindow.mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ insetsPolicy.updateBarControlTarget(mAppWindow);
+ assertNull(displayPolicy.mInputConsumer);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index f831287..2444c24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -221,7 +221,7 @@
addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
.getControllableInsetProvider().getSource().setVisible(false);
addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
- .getControllableInsetProvider().getSource().setVisible(true);
+ .getControllableInsetProvider().setServerVisible(true);
final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index ea933df..5005c07 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -46,6 +46,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -276,6 +277,31 @@
}
@Test
+ public void testAddTasksInVisibilityUpdate_expectNoTrim() {
+ mRecentTasks.setOnlyTestVisibleRange();
+ mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
+ mRecentTasks.add(mTasks.get(0));
+
+ doAnswer(invocation -> {
+ assertTrue(mSupervisor.inActivityVisibilityUpdate());
+ // Simulate an activity is resumed by EnsureActivitiesVisibleHelper. If its state is
+ // change to RESUMED, it will also be added to recents.
+ mRecentTasks.add(mTasks.get(1));
+ invocation.callRealMethod();
+ return null;
+ }).when(mSupervisor).endActivityVisibilityUpdate();
+
+ mTaskContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */, false /* notifyClients */);
+
+ assertFalse(mSupervisor.inActivityVisibilityUpdate());
+ assertThat(mCallbacksRecorder.mAdded).hasSize(2);
+ // Expect nothing is trimmed because we don't want the loop of ensure-visibility to be
+ // impacted by the arbitrary number of task removals.
+ assertNoTasksTrimmed();
+ }
+
+ @Test
public void testAddTasksMultipleTasks_expectRemovedNoTrim() {
// Add multiple same-affinity non-document tasks, ensure that it removes the other task,
// but that it does not trim it
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 5e8de87..31a102a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -64,6 +64,8 @@
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.SystemUtil;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -343,7 +345,10 @@
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(displayId);
- final Activity activity = mInstrumentation.startActivitySync(intent, options.toBundle());
+
+ final Activity activity = SystemUtil.runWithShellPermissionIdentity(
+ () -> mInstrumentation.startActivitySync(intent, options.toBundle()),
+ "android.permission.ACTIVITY_EMBEDDING");
waitForIdle();
assertEquals(displayId, activity.getDisplayId());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 60875de..fb24d86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -49,7 +49,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -67,16 +66,12 @@
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.service.voice.IVoiceInteractionSession;
import android.util.DisplayMetrics;
import android.util.Xml;
import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.server.wm.Task.TaskFactory;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -122,11 +117,6 @@
assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
}
- @Test
- public void testDefaultTaskFactoryNotNull() throws Exception {
- assertNotNull(Task.getTaskFactory());
- }
-
/** Ensure we have no chance to modify the original intent. */
@Test
public void testCopyBaseIntentForTaskInfo() {
@@ -139,23 +129,6 @@
}
@Test
- public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
- TestTaskFactory factory = new TestTaskFactory();
- Task.setTaskFactory(factory);
-
- try {
- assertFalse(factory.mCreated);
-
- Task.create(mService, 0 /*taskId*/, 0 /*activityType*/,
- new ActivityInfo(), new Intent(), false /* createdByOrganizer */);
-
- assertTrue(factory.mCreated);
- } finally {
- Task.setTaskFactory(null);
- }
- }
-
- @Test
public void testReturnsToHomeStack() throws Exception {
final Task task = createTask(1);
spyOn(task);
@@ -448,6 +421,21 @@
}
@Test
+ public void testFullScreenTaskNotAdjustedByMinimalSize() {
+ final Task fullscreenTask = new TaskBuilder(mSupervisor).build();
+ final Rect originalTaskBounds = new Rect(fullscreenTask.getBounds());
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0 /* width */, 0 /* widthFraction */,
+ 0 /* height */, 0 /* heightFraction */, 0 /* gravity */,
+ originalTaskBounds.width() * 2 /* minWidth */,
+ originalTaskBounds.height() * 2 /* minHeight */);
+ fullscreenTask.setMinDimensions(aInfo);
+ fullscreenTask.onConfigurationChanged(fullscreenTask.getParent().getConfiguration());
+
+ assertEquals(originalTaskBounds, fullscreenTask.getBounds());
+ }
+
+ @Test
public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
@@ -525,8 +513,9 @@
info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
info.targetActivity = targetClassName;
- final Task task = Task.create(mService, 1 /* taskId */, info, intent,
- null /* voiceSession */, null /* voiceInteractor */, null /*stack*/);
+ final Task task = new ActivityStack(mService, 1 /* taskId */, info, intent,
+ null /* voiceSession */, null /* voiceInteractor */, null /* taskDescriptor */,
+ null /*stack*/);
assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
task.intent.getComponent().getClassName());
@@ -1023,48 +1012,4 @@
0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
null /*stack*/);
}
-
- private static class TestTaskFactory extends TaskFactory {
- private boolean mCreated = false;
-
- @Override
- Task create(ActivityTaskManagerService service, int taskId, int activityType,
- ActivityInfo info, Intent intent, boolean createdByOrganizer) {
- mCreated = true;
- return null;
- }
-
- @Override
- Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor, ActivityStack stack) {
- mCreated = true;
- return null;
- }
-
- @Override
- Task create(ActivityTaskManagerService service, int taskId, Intent intent,
- Intent affinityIntent, String affinity, String rootAffinity,
- ComponentName realActivity,
- ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
- boolean askedCompatMode, int userId, int effectiveUid, String lastDescription,
- long lastTimeMoved,
- boolean neverRelinquishIdentity,
- ActivityManager.TaskDescription lastTaskDescription,
- int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
- int callingUid, String callingPackage, String callingFeatureId, int resizeMode,
- boolean supportsPictureInPicture,
- boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
- int minHeight, ActivityStack stack) {
- mCreated = true;
- return null;
- }
-
- @Override
- Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
- throws IOException, XmlPullParserException {
- mCreated = true;
- return null;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 9872faa..4e92ea0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
@@ -41,6 +42,7 @@
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
@@ -56,8 +58,10 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
/**
* Build/Install/Run:
@@ -391,6 +395,42 @@
}
};
+ @Presubmit
+ @FlakyTest(bugId = 150409355)
+ @Test
+ public void testNotifyTaskRequestedOrientationChanged() throws Exception {
+ final ArrayBlockingQueue<int[]> taskIdAndOrientationQueue = new ArrayBlockingQueue<>(10);
+ registerTaskStackChangedListener(new TaskStackListener() {
+ @Override
+ public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ int[] taskIdAndOrientation = new int[2];
+ taskIdAndOrientation[0] = taskId;
+ taskIdAndOrientation[1] = requestedOrientation;
+ taskIdAndOrientationQueue.offer(taskIdAndOrientation);
+ }
+ });
+
+ final LandscapeActivity activity =
+ (LandscapeActivity) startTestActivity(LandscapeActivity.class);
+
+ int[] taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
+ candidate -> candidate[0] == activity.getTaskId());
+ assertNotNull(taskIdAndOrientation);
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, taskIdAndOrientation[1]);
+
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
+ taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
+ candidate -> candidate[0] == activity.getTaskId());
+ assertNotNull(taskIdAndOrientation);
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, taskIdAndOrientation[1]);
+
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
+ candidate -> candidate[0] == activity.getTaskId());
+ assertNotNull(taskIdAndOrientation);
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, taskIdAndOrientation[1]);
+ }
+
/**
* Starts the provided activity and returns the started instance.
*/
@@ -432,6 +472,19 @@
}
}
+ private <T> T waitForResult(ArrayBlockingQueue<T> queue, Predicate<T> predicate) {
+ try {
+ final long timeout = SystemClock.uptimeMillis() + TimeUnit.SECONDS.toMillis(15);
+ T result;
+ do {
+ result = queue.poll(timeout - SystemClock.uptimeMillis(), TimeUnit.MILLISECONDS);
+ } while (result != null && !predicate.test(result));
+ return result;
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
public static class TestActivity extends Activity {
boolean mIsResumed = false;
@@ -563,4 +616,6 @@
// Activity that has {@link android.R.attr#resizeableActivity} attribute set to {@code true}
public static class ActivityInActivityView extends TestActivity {}
+
+ public static class LandscapeActivity extends TestActivity {}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 9fdb9d8..d65b084 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -204,7 +204,7 @@
.when(windowConfiguration).getWindowingMode();
// Prevent adjust task dimensions
- doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
+ doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any(), any());
final Rect stackBounds = new Rect(200, 200, 800, 1000);
// Update surface position and size by the given bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 520ac19..373f363 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -271,6 +271,29 @@
assertEquals(WINDOWING_MODE_FULLSCREEN, token.getWindowingMode());
}
+ @Test
+ public void testFixedRotationRecentsAnimatingTask() {
+ final RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
+ doReturn(true).when(recentsController).isWallpaperVisible(eq(mAppWindow));
+ mWm.setRecentsAnimationController(recentsController);
+
+ mAppWindow.mActivityRecord.applyFixedRotationTransform(mDisplayContent.getDisplayInfo(),
+ mDisplayContent.mDisplayFrames, mDisplayContent.getConfiguration());
+ mAppWindow.mActivityRecord.mVisibleRequested = true;
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+
+ assertEquals(mAppWindow, mDisplayContent.mWallpaperController.getWallpaperTarget());
+ // Wallpaper should link the transform of its target.
+ assertTrue(mAppWindow.mActivityRecord.hasFixedRotationTransform());
+
+ mAppWindow.mActivityRecord.finishFixedRotationTransform();
+ // Invisible requested activity should not share its rotation transform.
+ mAppWindow.mActivityRecord.mVisibleRequested = false;
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+
+ assertFalse(mAppWindow.mActivityRecord.hasFixedRotationTransform());
+ }
+
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
.setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 353c781..00439f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -23,6 +23,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
@@ -35,6 +36,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.DisplayArea.Type.ANY;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -839,6 +841,36 @@
verifyWindowContainerApplyAnimation(stack, activity);
}
+ @Test
+ public void testGetDisplayArea() {
+ // WindowContainer
+ final WindowContainer windowContainer = new WindowContainer(mWm);
+
+ assertNull(windowContainer.getDisplayArea());
+
+ // ActivityStack > WindowContainer
+ final ActivityStack activityStack = createTaskStackOnDisplay(mDisplayContent);
+ activityStack.addChild(windowContainer, 0);
+ activityStack.setParent(null);
+
+ assertNull(windowContainer.getDisplayArea());
+ assertNull(activityStack.getDisplayArea());
+
+ // TaskDisplayArea > ActivityStack > WindowContainer
+ final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(
+ mDisplayContent, mWm, "TaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
+ taskDisplayArea.addChild(activityStack, 0);
+
+ assertEquals(taskDisplayArea, windowContainer.getDisplayArea());
+ assertEquals(taskDisplayArea, activityStack.getDisplayArea());
+ assertEquals(taskDisplayArea, taskDisplayArea.getDisplayArea());
+
+ // DisplayArea
+ final DisplayArea displayArea = new DisplayArea(mWm, ANY, "DisplayArea");
+
+ assertEquals(displayArea, displayArea.getDisplayArea());
+ }
+
private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act) {
// Initial remote animation for app transition.
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 79b9ae1..f52905e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -16,21 +16,30 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+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.os.Process.INVALID_UID;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -40,6 +49,10 @@
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
+/**
+ * Build/Install/Run:
+ * atest WmTests:WindowManagerServiceTests
+ */
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
@@ -105,4 +118,70 @@
mWm.removeWindowToken(token, mDisplayContent.getDisplayId());
}
+
+ @Test
+ public void testTaskFocusChange_stackNotHomeType_focusChanges() throws RemoteException {
+ DisplayContent display = createNewDisplay();
+ // Current focused window
+ ActivityStack focusedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
+ Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
+ mDisplayContent.mCurrentFocus = focusedWindow;
+ // Tapped task
+ ActivityStack tappedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, display);
+ Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ spyOn(mWm.mActivityTaskManager);
+
+ mWm.handleTaskFocusChange(tappedTask);
+
+ verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ }
+
+ @Test
+ public void testTaskFocusChange_stackHomeTypeWithSameTaskDisplayArea_focusDoesNotChange()
+ throws RemoteException {
+ DisplayContent display = createNewDisplay();
+ // Current focused window
+ ActivityStack focusedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
+ Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
+ mDisplayContent.mCurrentFocus = focusedWindow;
+ // Tapped home task
+ ActivityStack tappedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, display);
+ Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ spyOn(mWm.mActivityTaskManager);
+
+ mWm.handleTaskFocusChange(tappedTask);
+
+ verify(mWm.mActivityTaskManager, never()).setFocusedTask(tappedTask.mTaskId);
+ }
+
+ @Test
+ public void testTaskFocusChange_stackHomeTypeWithDifferentTaskDisplayArea_focusChanges()
+ throws RemoteException {
+ DisplayContent display = createNewDisplay();
+ TaskDisplayArea secondTda =
+ new TaskDisplayArea(display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST);
+ display.mDisplayAreaPolicy.mRoot.addChild(secondTda, 1);
+ display.mDisplayAreaPolicy.mTaskDisplayAreas.add(secondTda);
+ // Current focused window
+ ActivityStack focusedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
+ Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
+ mDisplayContent.mCurrentFocus = focusedWindow;
+ // Tapped home task on another task display area
+ ActivityStack tappedStack = createTaskStackOnTaskDisplayArea(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, secondTda);
+ Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ spyOn(mWm.mActivityTaskManager);
+
+ mWm.handleTaskFocusChange(tappedTask);
+
+ verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index aa68c69..2ea58a0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -507,7 +507,7 @@
Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
Configuration c = new Configuration(task1.getRequestedOverrideConfiguration());
c.windowConfiguration.setBounds(newSize);
- doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
+ doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any(), any());
task1.onRequestedOverrideConfigurationChanged(c);
assertEquals(newSize, stack.getBounds());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 94c204ab..0eaab52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -304,6 +304,20 @@
}
}
+ ActivityStack createTaskStackOnTaskDisplayArea(
+ int windowingMode, int activityType, TaskDisplayArea tda) {
+ synchronized (mWm.mGlobalLock) {
+ return new ActivityTestsBase.StackBuilder(
+ tda.mDisplayContent.mWmService.mAtmService.mRootWindowContainer)
+ .setTaskDisplayArea(tda)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setCreateActivity(false)
+ .setIntent(new Intent())
+ .build();
+ }
+ }
+
/** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
Task createTaskInStack(ActivityStack stack, int userId) {
return WindowTestUtils.createTaskInStack(mWm, stack, userId);
diff --git a/services/usage/Android.bp b/services/usage/Android.bp
index 156bf33..463673f 100644
--- a/services/usage/Android.bp
+++ b/services/usage/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.usage",
+ defaults: ["services_defaults"],
srcs: [":services.usage-sources"],
libs: ["services.core"],
}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 8fadf5e..5ee3b48 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -253,10 +253,6 @@
}
break;
}
- if (event.mTimeStamp == 0) {
- //mTimestamp not set, assume default value 0 plus beginTime
- event.mTimeStamp = beginTime;
- }
return event;
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 932784d..463fc37 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -149,10 +149,6 @@
break;
}
}
- if (stats.mLastTimeUsed == 0) {
- // mLastTimeUsed was not assigned, assume default value of 0 plus beginTime;
- stats.mLastTimeUsed = statsOut.beginTime;
- }
proto.end(token);
}
@@ -289,10 +285,6 @@
configActive = proto.readBoolean(IntervalStatsProto.Configuration.ACTIVE);
break;
case ProtoInputStream.NO_MORE_FIELDS:
- if (configStats.mLastTimeActive == 0) {
- //mLastTimeActive was not assigned, assume default value of 0 plus beginTime
- configStats.mLastTimeActive = statsOut.beginTime;
- }
if (configActive) {
statsOut.activeConfiguration = configStats.mConfiguration;
}
@@ -336,21 +328,21 @@
// Package not in Stringpool for some reason, write full string instead
proto.write(IntervalStatsProto.UsageStats.PACKAGE, usageStats.mPackageName);
}
- // Time attributes stored as an offset of the beginTime.
- proto.write(IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS,
- usageStats.mLastTimeUsed - stats.beginTime);
+ UsageStatsProtoV2.writeOffsetTimestamp(proto,
+ IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS,
+ usageStats.mLastTimeUsed, stats.beginTime);
proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS,
usageStats.mTotalTimeInForeground);
proto.write(IntervalStatsProto.UsageStats.LAST_EVENT,
usageStats.mLastEvent);
- // Time attributes stored as an offset of the beginTime.
- proto.write(IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS,
- usageStats.mLastTimeForegroundServiceUsed - stats.beginTime);
+ UsageStatsProtoV2.writeOffsetTimestamp(proto,
+ IntervalStatsProto.UsageStats.LAST_TIME_SERVICE_USED_MS,
+ usageStats.mLastTimeForegroundServiceUsed, stats.beginTime);
proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_SERVICE_USED_MS,
usageStats.mTotalTimeForegroundServiceUsed);
- // Time attributes stored as an offset of the beginTime.
- proto.write(IntervalStatsProto.UsageStats.LAST_TIME_VISIBLE_MS,
- usageStats.mLastTimeVisible - stats.beginTime);
+ UsageStatsProtoV2.writeOffsetTimestamp(proto,
+ IntervalStatsProto.UsageStats.LAST_TIME_VISIBLE_MS,
+ usageStats.mLastTimeVisible, stats.beginTime);
proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS,
usageStats.mTotalTimeVisible);
proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount);
@@ -411,8 +403,9 @@
throws IllegalArgumentException {
final long token = proto.start(fieldId);
configStats.mConfiguration.dumpDebug(proto, IntervalStatsProto.Configuration.CONFIG);
- proto.write(IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS,
- configStats.mLastTimeActive - stats.beginTime);
+ UsageStatsProtoV2.writeOffsetTimestamp(proto,
+ IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS,
+ configStats.mLastTimeActive, stats.beginTime);
proto.write(IntervalStatsProto.Configuration.TOTAL_TIME_ACTIVE_MS,
configStats.mTotalTimeActive);
proto.write(IntervalStatsProto.Configuration.COUNT, configStats.mActivationCount);
@@ -439,7 +432,8 @@
proto.write(IntervalStatsProto.Event.CLASS, event.mClass);
}
}
- proto.write(IntervalStatsProto.Event.TIME_MS, event.mTimeStamp - stats.beginTime);
+ UsageStatsProtoV2.writeOffsetTimestamp(proto, IntervalStatsProto.Event.TIME_MS,
+ event.mTimeStamp, stats.beginTime);
proto.write(IntervalStatsProto.Event.FLAGS, event.mFlags);
proto.write(IntervalStatsProto.Event.TYPE, event.mEventType);
proto.write(IntervalStatsProto.Event.INSTANCE_ID, event.mInstanceId);
@@ -566,10 +560,6 @@
}
break;
case ProtoInputStream.NO_MORE_FIELDS:
- if (statsOut.endTime == 0) {
- // endTime not assigned, assume default value of 0 plus beginTime
- statsOut.endTime = statsOut.beginTime;
- }
statsOut.upgradeIfNeeded();
return;
}
@@ -585,7 +575,8 @@
public static void write(OutputStream out, IntervalStats stats)
throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
- proto.write(IntervalStatsProto.END_TIME_MS, stats.endTime - stats.beginTime);
+ proto.write(IntervalStatsProto.END_TIME_MS,
+ UsageStatsProtoV2.getOffsetTimestamp(stats.endTime, stats.beginTime));
proto.write(IntervalStatsProto.MAJOR_VERSION, stats.majorVersion);
proto.write(IntervalStatsProto.MINOR_VERSION, stats.minorVersion);
// String pool should be written before the rest of the usage stats
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index e4aa9fe..e6d2841 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -30,6 +30,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.concurrent.TimeUnit;
/**
* UsageStats reader/writer V2 for Protocol Buffer format.
@@ -37,6 +38,8 @@
final class UsageStatsProtoV2 {
private static final String TAG = "UsageStatsProtoV2";
+ private static final long ONE_HOUR_MS = TimeUnit.HOURS.toMillis(1);
+
// Static-only utility class.
private UsageStatsProtoV2() {}
@@ -88,10 +91,6 @@
UsageStatsObfuscatedProto.TOTAL_TIME_VISIBLE_MS);
break;
case ProtoInputStream.NO_MORE_FIELDS:
- // mLastTimeUsed was not read, assume default value of 0 plus beginTime
- if (stats.mLastTimeUsed == 0) {
- stats.mLastTimeUsed = beginTime;
- }
return stats;
}
}
@@ -219,10 +218,6 @@
IntervalStatsObfuscatedProto.Configuration.ACTIVE);
break;
case ProtoInputStream.NO_MORE_FIELDS:
- // mLastTimeActive was not assigned, assume default value of 0 plus beginTime
- if (configStats.mLastTimeActive == 0) {
- configStats.mLastTimeActive = stats.beginTime;
- }
if (configActive) {
stats.activeConfiguration = configStats.mConfiguration;
}
@@ -282,27 +277,40 @@
EventObfuscatedProto.LOCUS_ID_TOKEN) - 1;
break;
case ProtoInputStream.NO_MORE_FIELDS:
- // timeStamp was not read, assume default value 0 plus beginTime
- if (event.mTimeStamp == 0) {
- event.mTimeStamp = beginTime;
- }
return event.mPackageToken == PackagesTokenData.UNASSIGNED_TOKEN ? null : event;
}
}
}
+ static void writeOffsetTimestamp(ProtoOutputStream proto, long fieldId,
+ long timestamp, long beginTime) {
+ // timestamps will only be written if they're after the begin time
+ // a grace period of one hour before the begin time is allowed because of rollover logic
+ final long rolloverGracePeriod = beginTime - ONE_HOUR_MS;
+ if (timestamp > rolloverGracePeriod) {
+ // time attributes are stored as an offset of the begin time (given offset)
+ proto.write(fieldId, getOffsetTimestamp(timestamp, beginTime));
+ }
+ }
+
+ static long getOffsetTimestamp(long timestamp, long offset) {
+ final long offsetTimestamp = timestamp - offset;
+ // add one ms to timestamp if 0 to ensure it's written to proto (default values are ignored)
+ return offsetTimestamp == 0 ? offsetTimestamp + 1 : offsetTimestamp;
+ }
+
private static void writeUsageStats(ProtoOutputStream proto, final long beginTime,
final UsageStats stats) throws IllegalArgumentException {
- // Time attributes stored as an offset of the beginTime.
proto.write(UsageStatsObfuscatedProto.PACKAGE_TOKEN, stats.mPackageToken + 1);
- proto.write(UsageStatsObfuscatedProto.LAST_TIME_ACTIVE_MS, stats.mLastTimeUsed - beginTime);
+ writeOffsetTimestamp(proto, UsageStatsObfuscatedProto.LAST_TIME_ACTIVE_MS,
+ stats.mLastTimeUsed, beginTime);
proto.write(UsageStatsObfuscatedProto.TOTAL_TIME_ACTIVE_MS, stats.mTotalTimeInForeground);
- proto.write(UsageStatsObfuscatedProto.LAST_TIME_SERVICE_USED_MS,
- stats.mLastTimeForegroundServiceUsed - beginTime);
+ writeOffsetTimestamp(proto, UsageStatsObfuscatedProto.LAST_TIME_SERVICE_USED_MS,
+ stats.mLastTimeForegroundServiceUsed, beginTime);
proto.write(UsageStatsObfuscatedProto.TOTAL_TIME_SERVICE_USED_MS,
stats.mTotalTimeForegroundServiceUsed);
- proto.write(UsageStatsObfuscatedProto.LAST_TIME_VISIBLE_MS,
- stats.mLastTimeVisible - beginTime);
+ writeOffsetTimestamp(proto, UsageStatsObfuscatedProto.LAST_TIME_VISIBLE_MS,
+ stats.mLastTimeVisible, beginTime);
proto.write(UsageStatsObfuscatedProto.TOTAL_TIME_VISIBLE_MS, stats.mTotalTimeVisible);
proto.write(UsageStatsObfuscatedProto.APP_LAUNCH_COUNT, stats.mAppLaunchCount);
try {
@@ -361,8 +369,8 @@
throws IllegalArgumentException {
configStats.mConfiguration.dumpDebug(proto,
IntervalStatsObfuscatedProto.Configuration.CONFIG);
- proto.write(IntervalStatsObfuscatedProto.Configuration.LAST_TIME_ACTIVE_MS,
- configStats.mLastTimeActive - statsBeginTime);
+ writeOffsetTimestamp(proto, IntervalStatsObfuscatedProto.Configuration.LAST_TIME_ACTIVE_MS,
+ configStats.mLastTimeActive, statsBeginTime);
proto.write(IntervalStatsObfuscatedProto.Configuration.TOTAL_TIME_ACTIVE_MS,
configStats.mTotalTimeActive);
proto.write(IntervalStatsObfuscatedProto.Configuration.COUNT, configStats.mActivationCount);
@@ -375,7 +383,7 @@
if (event.mClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
proto.write(EventObfuscatedProto.CLASS_TOKEN, event.mClassToken + 1);
}
- proto.write(EventObfuscatedProto.TIME_MS, event.mTimeStamp - statsBeginTime);
+ writeOffsetTimestamp(proto, EventObfuscatedProto.TIME_MS, event.mTimeStamp, statsBeginTime);
proto.write(EventObfuscatedProto.FLAGS, event.mFlags);
proto.write(EventObfuscatedProto.TYPE, event.mEventType);
proto.write(EventObfuscatedProto.INSTANCE_ID, event.mInstanceId);
@@ -489,10 +497,6 @@
}
break;
case ProtoInputStream.NO_MORE_FIELDS:
- // endTime not assigned, assume default value of 0 plus beginTime
- if (stats.endTime == 0) {
- stats.endTime = stats.beginTime;
- }
// update the begin and end time stamps for all usage stats
final int usageStatsSize = stats.packageStatsObfuscated.size();
for (int i = 0; i < usageStatsSize; i++) {
@@ -514,7 +518,8 @@
public static void write(OutputStream out, IntervalStats stats)
throws IOException, IllegalArgumentException {
final ProtoOutputStream proto = new ProtoOutputStream(out);
- proto.write(IntervalStatsObfuscatedProto.END_TIME_MS, stats.endTime - stats.beginTime);
+ proto.write(IntervalStatsObfuscatedProto.END_TIME_MS,
+ getOffsetTimestamp(stats.endTime, stats.beginTime));
proto.write(IntervalStatsObfuscatedProto.MAJOR_VERSION, stats.majorVersion);
proto.write(IntervalStatsObfuscatedProto.MINOR_VERSION, stats.minorVersion);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b7779fd..4e75b73 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -1166,6 +1166,7 @@
byte[] getBackupPayload(String key){
checkAndGetTimeLocked();
+ persistActiveStats();
return mDatabase.getBackupPayload(key);
}
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index a9474c1..4e98409 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.usb",
+ defaults: ["services_defaults"],
srcs: [":services.usb-sources"],
libs: [
diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp
index 85b96f34..47129ad 100644
--- a/services/voiceinteraction/Android.bp
+++ b/services/voiceinteraction/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.voiceinteraction",
+ defaults: ["services_defaults"],
srcs: [":services.voiceinteraction-sources"],
libs: ["services.core"],
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 170bee8..42e2bbf 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -443,6 +443,8 @@
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ enforceDetectionPermissions(detectionService);
+
if (!isInitialized()) return STATUS_ERROR;
if (DEBUG) {
Slog.i(TAG, "startRecognition(): id = " + soundModelId);
@@ -1532,6 +1534,16 @@
}
}
+ private void enforceDetectionPermissions(ComponentName detectionService) {
+ PackageManager packageManager = mContext.getPackageManager();
+ String packageName = detectionService.getPackageName();
+ if (packageManager.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(detectionService.getPackageName() + " does not have"
+ + " permission " + Manifest.permission.CAPTURE_AUDIO_HOTWORD);
+ }
+ }
+
//=================================================================
// For logging
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
index f56c2cf..3975fd2 100644
--- a/services/wifi/Android.bp
+++ b/services/wifi/Android.bp
@@ -7,6 +7,7 @@
java_library_static {
name: "services.wifi",
+ defaults: ["services_defaults"],
srcs: [
":services.wifi-sources",
],
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
index 1d8119d..8c9d4df 100644
--- a/startop/iorap/TEST_MAPPING
+++ b/startop/iorap/TEST_MAPPING
@@ -2,9 +2,6 @@
"presubmit": [
{
"name": "libiorap-java-tests"
- },
- {
- "name": "iorap-functional-tests"
}
],
"imports": [
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a716b37..56cba1d 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2102,12 +2102,12 @@
private void abort(String callId) {
- Log.d(this, "abort %s", callId);
+ Log.i(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort();
}
private void answerVideo(String callId, int videoState) {
- Log.d(this, "answerVideo %s", callId);
+ Log.i(this, "answerVideo %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer(videoState);
} else {
@@ -2116,7 +2116,7 @@
}
private void answer(String callId) {
- Log.d(this, "answer %s", callId);
+ Log.i(this, "answer %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer();
} else {
@@ -2125,12 +2125,12 @@
}
private void deflect(String callId, Uri address) {
- Log.d(this, "deflect %s", callId);
+ Log.i(this, "deflect %s", callId);
findConnectionForAction(callId, "deflect").onDeflect(address);
}
private void reject(String callId) {
- Log.d(this, "reject %s", callId);
+ Log.i(this, "reject %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "reject").onReject();
} else {
@@ -2139,34 +2139,34 @@
}
private void reject(String callId, String rejectWithMessage) {
- Log.d(this, "reject %s with message", callId);
+ Log.i(this, "reject %s with message", callId);
findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
}
private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
- Log.d(this, "reject %s with reason %d", callId, rejectReason);
+ Log.i(this, "reject %s with reason %d", callId, rejectReason);
findConnectionForAction(callId, "reject").onReject(rejectReason);
}
private void transfer(String callId, Uri number, boolean isConfirmationRequired) {
- Log.d(this, "transfer %s", callId);
+ Log.i(this, "transfer %s", callId);
findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired);
}
private void consultativeTransfer(String callId, String otherCallId) {
- Log.d(this, "consultativeTransfer %s", callId);
+ Log.i(this, "consultativeTransfer %s", callId);
Connection connection1 = findConnectionForAction(callId, "consultativeTransfer");
Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer");
connection1.onTransfer(connection2);
}
private void silence(String callId) {
- Log.d(this, "silence %s", callId);
+ Log.i(this, "silence %s", callId);
findConnectionForAction(callId, "silence").onSilence();
}
private void disconnect(String callId) {
- Log.d(this, "disconnect %s", callId);
+ Log.i(this, "disconnect %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "disconnect").onDisconnect();
} else {
@@ -2175,7 +2175,7 @@
}
private void hold(String callId) {
- Log.d(this, "hold %s", callId);
+ Log.i(this, "hold %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "hold").onHold();
} else {
@@ -2184,7 +2184,7 @@
}
private void unhold(String callId) {
- Log.d(this, "unhold %s", callId);
+ Log.i(this, "unhold %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "unhold").onUnhold();
} else {
@@ -2193,7 +2193,7 @@
}
private void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
- Log.d(this, "onAudioStateChanged %s %s", callId, callAudioState);
+ Log.i(this, "onAudioStateChanged %s %s", callId, callAudioState);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "onCallAudioStateChanged").setCallAudioState(
callAudioState);
@@ -2204,7 +2204,7 @@
}
private void playDtmfTone(String callId, char digit) {
- Log.d(this, "playDtmfTone %s %c", callId, digit);
+ Log.i(this, "playDtmfTone %s %c", callId, digit);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
} else {
@@ -2213,7 +2213,7 @@
}
private void stopDtmfTone(String callId) {
- Log.d(this, "stopDtmfTone %s", callId);
+ Log.i(this, "stopDtmfTone %s", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone();
} else {
@@ -2222,7 +2222,7 @@
}
private void conference(String callId1, String callId2) {
- Log.d(this, "conference %s, %s", callId1, callId2);
+ Log.i(this, "conference %s, %s", callId1, callId2);
// Attempt to get second connection or conference.
Connection connection2 = findConnectionForAction(callId2, "conference");
@@ -2269,7 +2269,7 @@
}
private void splitFromConference(String callId) {
- Log.d(this, "splitFromConference(%s)", callId);
+ Log.i(this, "splitFromConference(%s)", callId);
Connection connection = findConnectionForAction(callId, "splitFromConference");
if (connection == getNullConnection()) {
@@ -2284,7 +2284,7 @@
}
private void mergeConference(String callId) {
- Log.d(this, "mergeConference(%s)", callId);
+ Log.i(this, "mergeConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "mergeConference");
if (conference != null) {
conference.onMerge();
@@ -2292,7 +2292,7 @@
}
private void swapConference(String callId) {
- Log.d(this, "swapConference(%s)", callId);
+ Log.i(this, "swapConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "swapConference");
if (conference != null) {
conference.onSwap();
@@ -2300,7 +2300,7 @@
}
private void addConferenceParticipants(String callId, List<Uri> participants) {
- Log.d(this, "addConferenceParticipants(%s)", callId);
+ Log.i(this, "addConferenceParticipants(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "addConferenceParticipants")
.onAddConferenceParticipants(participants);
@@ -2318,7 +2318,7 @@
* @param callId The ID of the call to pull.
*/
private void pullExternalCall(String callId) {
- Log.d(this, "pullExternalCall(%s)", callId);
+ Log.i(this, "pullExternalCall(%s)", callId);
Connection connection = findConnectionForAction(callId, "pullExternalCall");
if (connection != null) {
connection.onPullExternalCall();
@@ -2335,7 +2335,7 @@
* @param extras Extras associated with the event.
*/
private void sendCallEvent(String callId, String event, Bundle extras) {
- Log.d(this, "sendCallEvent(%s, %s)", callId, event);
+ Log.i(this, "sendCallEvent(%s, %s)", callId, event);
Connection connection = findConnectionForAction(callId, "sendCallEvent");
if (connection != null) {
connection.onCallEvent(event, extras);
@@ -2348,7 +2348,7 @@
* @param callId The ID of the call which completed handover.
*/
private void notifyHandoverComplete(String callId) {
- Log.d(this, "notifyHandoverComplete(%s)", callId);
+ Log.i(this, "notifyHandoverComplete(%s)", callId);
Connection connection = findConnectionForAction(callId, "notifyHandoverComplete");
if (connection != null) {
connection.onHandoverComplete();
@@ -2368,7 +2368,7 @@
* @param extras The new extras bundle.
*/
private void handleExtrasChanged(String callId, Bundle extras) {
- Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras);
+ Log.i(this, "handleExtrasChanged(%s, %s)", callId, extras);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
} else if (mConferenceById.containsKey(callId)) {
@@ -2377,7 +2377,7 @@
}
private void startRtt(String callId, Connection.RttTextStream rttTextStream) {
- Log.d(this, "startRtt(%s)", callId);
+ Log.i(this, "startRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "startRtt").onStartRtt(rttTextStream);
} else if (mConferenceById.containsKey(callId)) {
@@ -2386,7 +2386,7 @@
}
private void stopRtt(String callId) {
- Log.d(this, "stopRtt(%s)", callId);
+ Log.i(this, "stopRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopRtt").onStopRtt();
} else if (mConferenceById.containsKey(callId)) {
@@ -2395,7 +2395,7 @@
}
private void handleRttUpgradeResponse(String callId, Connection.RttTextStream rttTextStream) {
- Log.d(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
+ Log.i(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "handleRttUpgradeResponse")
.handleRttUpgradeResponse(rttTextStream);
@@ -2405,7 +2405,7 @@
}
private void onPostDialContinue(String callId, boolean proceed) {
- Log.d(this, "onPostDialContinue(%s)", callId);
+ Log.i(this, "onPostDialContinue(%s)", callId);
findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 4f6a9d6..a90d053 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,9 @@
package android.telecom;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
@@ -29,8 +31,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.Locale;
+import java.util.stream.Collectors;
/**
* Manages logging for the entire module.
@@ -212,6 +216,16 @@
return getSessionManager().getExternalSession();
}
+ /**
+ * Retrieves external session information, providing a context for the recipient of the session
+ * info where the external session came from.
+ * @param ownerInfo The external owner info.
+ * @return New {@link Session.Info} instance with owner info set.
+ */
+ public static Session.Info getExternalSession(@NonNull String ownerInfo) {
+ return getSessionManager().getExternalSession(ownerInfo);
+ }
+
public static void cancelSubsession(Session subsession) {
getSessionManager().cancelSubsession(subsession);
}
@@ -481,4 +495,34 @@
}
return String.format(Locale.US, "%s: %s%s", prefix, msg, sessionPostfix);
}
+
+ /**
+ * Generates an abbreviated version of the package name from a component.
+ * E.g. com.android.phone becomes cap
+ * @param componentName The component name to abbreviate.
+ * @return Abbreviation of empty string if component is null.
+ * @hide
+ */
+ public static String getPackageAbbreviation(ComponentName componentName) {
+ if (componentName == null) {
+ return "";
+ }
+ return getPackageAbbreviation(componentName.getPackageName());
+ }
+
+ /**
+ * Generates an abbreviated version of the package name.
+ * E.g. com.android.phone becomes cap
+ * @param packageName The packageName name to abbreviate.
+ * @return Abbreviation of empty string if package is null.
+ * @hide
+ */
+ public static String getPackageAbbreviation(String packageName) {
+ if (packageName == null) {
+ return "";
+ }
+ return Arrays.stream(packageName.split("\\."))
+ .map(s -> s.substring(0,1))
+ .collect(Collectors.joining(""));
+ }
}
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
index 8d3f4e1..4aa3614 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -17,6 +17,7 @@
package android.telecom.Logging;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Log;
@@ -59,10 +60,12 @@
public static class Info implements Parcelable {
public final String sessionId;
public final String methodPath;
+ public final String ownerInfo;
- private Info(String id, String path) {
+ private Info(String id, String path, String owner) {
sessionId = id;
methodPath = path;
+ ownerInfo = owner;
}
public static Info getInfo (Session s) {
@@ -70,7 +73,28 @@
// not get multiple stacking external sessions (unless we have DEBUG level logging or
// lower).
return new Info(s.getFullSessionId(), s.getFullMethodPath(
- !Log.DEBUG && s.isSessionExternal()));
+ !Log.DEBUG && s.isSessionExternal()), s.getOwnerInfo());
+ }
+
+ public static Info getExternalInfo(Session s, @Nullable String ownerInfo) {
+ // When creating session information for an existing session, the caller may pass in a
+ // context to be passed along to the recipient of the external session info.
+ // So, for example, if telecom has an active session with owner 'cad', and Telecom is
+ // calling into Telephony and providing external session info, it would pass in 'cast'
+ // as the owner info. This would result in Telephony seeing owner info 'cad/cast',
+ // which would make it very clear in the Telephony logs the chain of package calls which
+ // ultimately resulted in the logs.
+ String newInfo = ownerInfo != null && s.getOwnerInfo() != null
+ // If we've got both, concatenate them.
+ ? s.getOwnerInfo() + "/" + ownerInfo
+ // Otherwise use whichever is present.
+ : ownerInfo != null ? ownerInfo : s.getOwnerInfo();
+
+ // Create Info based on the truncated method path if the session is external, so we do
+ // not get multiple stacking external sessions (unless we have DEBUG level logging or
+ // lower).
+ return new Info(s.getFullSessionId(), s.getFullMethodPath(
+ !Log.DEBUG && s.isSessionExternal()), newInfo);
}
/** Responsible for creating Info objects for deserialized Parcels. */
@@ -80,7 +104,8 @@
public Info createFromParcel(Parcel source) {
String id = source.readString();
String methodName = source.readString();
- return new Info(id, methodName);
+ String ownerInfo = source.readString();
+ return new Info(id, methodName, ownerInfo);
}
@Override
@@ -100,6 +125,7 @@
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(sessionId);
destination.writeString(methodPath);
+ destination.writeString(ownerInfo);
}
}
@@ -206,6 +232,14 @@
return Info.getInfo(this);
}
+ public Info getExternalInfo(@Nullable String ownerInfo) {
+ return Info.getExternalInfo(this, ownerInfo);
+ }
+
+ public String getOwnerInfo() {
+ return mOwnerInfo;
+ }
+
@VisibleForTesting
public String getSessionId() {
return mSessionId;
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
index ac30058..67e5eab 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -16,6 +16,7 @@
package android.telecom.Logging;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -180,7 +181,7 @@
Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION);
Session externalSession = new Session(Session.EXTERNAL_INDICATOR + sessionInfo.sessionId,
sessionInfo.methodPath, System.currentTimeMillis(),
- false /*isStartedFromActiveSession*/, null);
+ false /*isStartedFromActiveSession*/, sessionInfo.ownerInfo);
externalSession.setIsExternal(true);
// Mark the external session as already completed, since we have no way of knowing when
// the external session actually has completed.
@@ -224,7 +225,7 @@
// Start execution time of the session will be overwritten in continueSession(...).
Session newSubsession = new Session(threadSession.getNextChildId(),
threadSession.getShortMethodName(), System.currentTimeMillis(),
- isStartedFromActiveSession, null);
+ isStartedFromActiveSession, threadSession.getOwnerInfo());
threadSession.addChild(newSubsession);
newSubsession.setParentSession(threadSession);
@@ -238,12 +239,18 @@
return newSubsession;
}
+ public synchronized Session.Info getExternalSession() {
+ return getExternalSession(null /* ownerInfo */);
+ }
+
/**
* Retrieve the information of the currently active Session. This information is parcelable and
* is used to create an external Session ({@link #startExternalSession(Session.Info, String)}).
* If there is no Session active, this method will return null.
+ * @param ownerInfo Owner information for the session.
+ * @return The session information
*/
- public synchronized Session.Info getExternalSession() {
+ public synchronized Session.Info getExternalSession(@Nullable String ownerInfo) {
int threadId = getCallingThreadId();
Session threadSession = mSessionMapper.get(threadId);
if (threadSession == null) {
@@ -251,8 +258,7 @@
"active.");
return null;
}
-
- return threadSession.getInfo();
+ return threadSession.getExternalInfo(ownerInfo);
}
/**
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 05480dc..f947d34 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -30,13 +30,16 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.telecom.Logging.Session;
import android.view.Surface;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
/**
* A connection provided to a {@link ConnectionService} by another {@code ConnectionService}
@@ -655,6 +658,8 @@
private int mCallerDisplayNamePresentation;
private RemoteConference mConference;
private Bundle mExtras;
+ private String mCallingPackage;
+ private String mCallingPackageAbbreviation;
/**
* @hide
@@ -667,6 +672,13 @@
mConnectionService = connectionService;
mConnected = true;
mState = Connection.STATE_INITIALIZING;
+ if (request != null && request.getExtras() != null
+ && request.getExtras().containsKey(
+ Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME)) {
+ mCallingPackage = request.getExtras().getString(
+ Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME);
+ mCallingPackageAbbreviation = Log.getPackageAbbreviation(mCallingPackage);
+ }
}
/**
@@ -705,6 +717,8 @@
Bundle newExtras = new Bundle();
newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
putExtras(newExtras);
+ mCallingPackage = callingPackage;
+ mCallingPackageAbbreviation = Log.getPackageAbbreviation(mCallingPackage);
}
/**
@@ -899,11 +913,14 @@
* Instructs this {@code RemoteConnection} to abort.
*/
public void abort() {
+ Log.startSession("RC.a", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.abort(mConnectionId, null /*Session.Info*/);
+ mConnectionService.abort(mConnectionId, Log.getExternalSession());
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -911,11 +928,14 @@
* Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer.
*/
public void answer() {
+ Log.startSession("RC.an", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.answer(mConnectionId, null /*Session.Info*/);
+ mConnectionService.answer(mConnectionId, Log.getExternalSession());
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -925,11 +945,14 @@
* @hide
*/
public void answer(int videoState) {
+ Log.startSession("RC.an2", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.answerVideo(mConnectionId, videoState, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -937,11 +960,14 @@
* Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject.
*/
public void reject() {
+ Log.startSession("RC.r", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.reject(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -949,11 +975,14 @@
* Instructs this {@code RemoteConnection} to go on hold.
*/
public void hold() {
+ Log.startSession("RC.h", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.hold(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -961,11 +990,14 @@
* Instructs this {@link Connection#STATE_HOLDING} call to release from hold.
*/
public void unhold() {
+ Log.startSession("RC.u", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.unhold(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -973,11 +1005,15 @@
* Instructs this {@code RemoteConnection} to disconnect.
*/
public void disconnect() {
+ Log.startSession("RC.d", getActiveOwnerInfo());
try {
if (mConnected) {
- mConnectionService.disconnect(mConnectionId, null /*Session.Info*/);
+ mConnectionService.disconnect(mConnectionId, Log.getExternalSession(
+ mCallingPackageAbbreviation));
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -991,11 +1027,14 @@
* value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
*/
public void playDtmfTone(char digit) {
+ Log.startSession("RC.pDT", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.playDtmfTone(mConnectionId, digit, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1007,11 +1046,14 @@
* currently playing, this method will do nothing.
*/
public void stopDtmfTone() {
+ Log.startSession("RC.sDT", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.stopDtmfTone(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1037,12 +1079,16 @@
* @param proceed Whether or not to continue with the post-dial sequence.
*/
public void postDialContinue(boolean proceed) {
+ Log.startSession("RC.pDC", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.onPostDialContinue(mConnectionId, proceed,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ // bliss
+ } finally {
+ Log.endSession();
}
}
@@ -1052,11 +1098,14 @@
* See {@link Call#pullExternalCall()} for more information.
*/
public void pullExternalCall() {
+ Log.startSession("RC.pEC", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.pullExternalCall(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1079,12 +1128,15 @@
* @param state The audio state of this {@code RemoteConnection}.
*/
public void setCallAudioState(CallAudioState state) {
+ Log.startSession("RC.sCAS", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.onCallAudioStateChanged(mConnectionId, state,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1095,12 +1147,15 @@
* @hide
*/
public void startRtt(@NonNull Connection.RttTextStream rttTextStream) {
+ Log.startSession("RC.sR", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(),
rttTextStream.getFdToInCall(), null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1110,11 +1165,14 @@
* @hide
*/
public void stopRtt() {
+ Log.startSession("RC.stR", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/);
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1128,6 +1186,7 @@
* the in-call app.
*/
public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) {
+ Log.startSession("RC.sRUR", getActiveOwnerInfo());
try {
if (mConnected) {
if (rttTextStream == null) {
@@ -1140,6 +1199,8 @@
}
}
} catch (RemoteException ignored) {
+ } finally {
+ Log.endSession();
}
}
@@ -1164,6 +1225,22 @@
return mConference;
}
+ /**
+ * Get the owner info for the currently active session. We want to make sure that any owner
+ * info from the original call into the connection manager gets retained so that the full
+ * context of the calls can be traced down to Telephony.
+ * Example: Telecom will provide owner info in it's external session info that indicates
+ * 'cast' as the calling owner.
+ * @return The active owner
+ */
+ private String getActiveOwnerInfo() {
+ Session.Info info = Log.getExternalSession();
+ if (info == null) {
+ return null;
+ }
+ return info.ownerInfo;
+ }
+
/** {@hide} */
String getId() {
return mConnectionId;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index eb553d3..f2f1412 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -399,7 +399,7 @@
* Optional extra for communicating the call network technology used by a
* {@link android.telecom.Connection} to Telecom and InCallUI.
*
- * @see {@code NETWORK_TYPE_*} in {@link android.telephony.TelephonyManager}.
+ * {@code NETWORK_TYPE_*} in {@link android.telephony.TelephonyManager}.
*/
public static final String EXTRA_CALL_NETWORK_TYPE =
"android.telecom.extra.CALL_NETWORK_TYPE";
diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
new file mode 100644
index 0000000..6c63755
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Telephony;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * This class provides utility functions related to CellBroadcast.
+ */
+public class CellBroadcastUtils {
+ private static final String TAG = "CellBroadcastUtils";
+ private static final boolean VDBG = false;
+
+ /**
+ * Utility method to query the default CBR's package name.
+ */
+ public static String getDefaultCellBroadcastReceiverPackageName(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ ResolveInfo resolveInfo = packageManager.resolveActivity(
+ new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION),
+ PackageManager.MATCH_SYSTEM_ONLY);
+ String packageName;
+
+ if (resolveInfo == null) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: no package found");
+ return null;
+ }
+
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+
+ if (VDBG) {
+ Log.d(TAG, "getDefaultCellBroadcastReceiverPackageName: found package: " + packageName);
+ }
+
+ if (TextUtils.isEmpty(packageName) || packageManager.checkPermission(
+ android.Manifest.permission.READ_CELL_BROADCASTS, packageName)
+ == PackageManager.PERMISSION_DENIED) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: returning null; "
+ + "permission check failed for : " + packageName);
+ return null;
+ }
+
+ return packageName;
+ }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 45dc7af..e9ee06c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -63,6 +63,7 @@
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.util.HandlerExecutor;
+import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
import com.android.telephony.Rlog;
@@ -139,23 +140,118 @@
public static final String CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY =
"cache_key.telephony.get_default_data_sub_id";
+ /** @hide */
+ public static final String CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY =
+ "cache_key.telephony.get_default_sms_sub_id";
+
+ /** @hide */
+ public static final String CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY =
+ "cache_key.telephony.get_active_data_sub_id";
+
+ /** @hide */
+ public static final String CACHE_KEY_SLOT_INDEX_PROPERTY =
+ "cache_key.telephony.get_slot_index";
+
private static final int MAX_CACHE_SIZE = 4;
- private static PropertyInvalidatedCache<Void, Integer> sDefaultSubIdCache =
- new PropertyInvalidatedCache<Void, Integer>(
- MAX_CACHE_SIZE, CACHE_KEY_DEFAULT_SUB_ID_PROPERTY) {
- @Override
- protected Integer recompute(Void query) {
- return getDefaultSubscriptionIdInternal();
- }};
+ private static class VoidPropertyInvalidatedCache<T>
+ extends PropertyInvalidatedCache<Void, T> {
+ private final FunctionalUtils.ThrowingFunction<ISub, T> mInterfaceMethod;
+ private final String mCacheKeyProperty;
+ private final T mDefaultValue;
- private static PropertyInvalidatedCache<Void, Integer> sDefaultDataSubIdCache =
- new PropertyInvalidatedCache<Void, Integer>(
- MAX_CACHE_SIZE, CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY) {
- @Override
- protected Integer recompute(Void query) {
- return getDefaultDataSubscriptionIdInternal();
- }};
+ VoidPropertyInvalidatedCache(
+ FunctionalUtils.ThrowingFunction<ISub, T> subscriptionInterfaceMethod,
+ String cacheKeyProperty,
+ T defaultValue) {
+ super(MAX_CACHE_SIZE, cacheKeyProperty);
+ mInterfaceMethod = subscriptionInterfaceMethod;
+ mCacheKeyProperty = cacheKeyProperty;
+ mDefaultValue = defaultValue;
+ }
+
+ @Override
+ protected T recompute(Void aVoid) {
+ T result = mDefaultValue;
+
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ result = mInterfaceMethod.applyOrThrow(iSub);
+ }
+ } catch (Exception ex) {
+ Rlog.w(LOG_TAG, "Failed to recompute cache key for " + mCacheKeyProperty);
+ }
+
+ if (VDBG) logd("recomputing " + mCacheKeyProperty + ", result = " + result);
+ return result;
+ }
+ }
+
+ private static class IntegerPropertyInvalidatedCache<T>
+ extends PropertyInvalidatedCache<Integer, T> {
+ private final FunctionalUtils.ThrowingBiFunction<ISub, Integer, T> mInterfaceMethod;
+ private final String mCacheKeyProperty;
+ private final T mDefaultValue;
+
+ IntegerPropertyInvalidatedCache(
+ FunctionalUtils.ThrowingBiFunction<ISub, Integer, T> subscriptionInterfaceMethod,
+ String cacheKeyProperty,
+ T defaultValue) {
+ super(MAX_CACHE_SIZE, cacheKeyProperty);
+ mInterfaceMethod = subscriptionInterfaceMethod;
+ mCacheKeyProperty = cacheKeyProperty;
+ mDefaultValue = defaultValue;
+ }
+
+ @Override
+ protected T recompute(Integer query) {
+ T result = mDefaultValue;
+
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ result = mInterfaceMethod.applyOrThrow(iSub, query);
+ }
+ } catch (Exception ex) {
+ Rlog.w(LOG_TAG, "Failed to recompute cache key for " + mCacheKeyProperty);
+ }
+
+ if (VDBG) logd("recomputing " + mCacheKeyProperty + ", result = " + result);
+ return result;
+ }
+ }
+
+ private static VoidPropertyInvalidatedCache<Integer> sDefaultSubIdCache =
+ new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
+ CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
+ INVALID_SUBSCRIPTION_ID);
+
+ private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache =
+ new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
+ CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY,
+ INVALID_SUBSCRIPTION_ID);
+
+ private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache =
+ new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
+ CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY,
+ INVALID_SUBSCRIPTION_ID);
+
+ private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache =
+ new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
+ CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY,
+ INVALID_SUBSCRIPTION_ID);
+
+ private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache =
+ new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
+ CACHE_KEY_SLOT_INDEX_PROPERTY,
+ INVALID_SIM_SLOT_INDEX);
+
+ /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */
+ private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache =
+ new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
+ CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
+ INVALID_PHONE_INDEX);
/**
* Generates a content {@link Uri} used to receive updates on simInfo change
@@ -1199,7 +1295,6 @@
}
return subInfo;
-
}
/**
@@ -1769,25 +1864,7 @@
* subscriptionId doesn't have an associated slot index.
*/
public static int getSlotIndex(int subscriptionId) {
- if (!isValidSubscriptionId(subscriptionId)) {
- if (DBG) {
- logd("[getSlotIndex]- supplied subscriptionId is invalid.");
- }
- }
-
- int result = INVALID_SIM_SLOT_INDEX;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- result = iSub.getSlotIndex(subscriptionId);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return result;
-
+ return sSlotIndexCache.query(subscriptionId);
}
/**
@@ -1826,27 +1903,7 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static int getPhoneId(int subId) {
- if (!isValidSubscriptionId(subId)) {
- if (DBG) {
- logd("[getPhoneId]- fail");
- }
- return INVALID_PHONE_INDEX;
- }
-
- int result = INVALID_PHONE_INDEX;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- result = iSub.getPhoneId(subId);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- if (VDBG) logd("[getPhoneId]- phoneId=" + result);
- return result;
-
+ return sPhoneIdCache.query(subId);
}
private static void logd(String msg) {
@@ -1870,22 +1927,6 @@
return sDefaultSubIdCache.query(null);
}
- private static int getDefaultSubscriptionIdInternal() {
- int subId = INVALID_SUBSCRIPTION_ID;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- subId = iSub.getDefaultSubId();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- if (VDBG) logd("getDefaultSubId=" + subId);
- return subId;
- }
-
/**
* Returns the system's default voice subscription id.
*
@@ -1972,19 +2013,7 @@
* @return the default SMS subscription Id.
*/
public static int getDefaultSmsSubscriptionId() {
- int subId = INVALID_SUBSCRIPTION_ID;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- subId = iSub.getDefaultSmsSubId();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
- return subId;
+ return sDefaultSmsSubIdCache.query(null);
}
/**
@@ -2039,22 +2068,6 @@
return sDefaultDataSubIdCache.query(null);
}
- private static int getDefaultDataSubscriptionIdInternal() {
- int subId = INVALID_SUBSCRIPTION_ID;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- subId = iSub.getDefaultDataSubId();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
- return subId;
- }
-
/**
* Set the subscription which will be used by default for data, with the subscription which
* the supplied subscription ID corresponds to; or throw a RuntimeException if the supplied
@@ -3285,14 +3298,7 @@
* SubscriptionManager.INVALID_SUBSCRIPTION_ID if not.
*/
public static int getActiveDataSubscriptionId() {
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- return iSub.getActiveDataSubscriptionId();
- }
- } catch (RemoteException ex) {
- }
- return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ return sActiveDataSubIdCache.query(null);
}
/**
@@ -3320,13 +3326,45 @@
PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY);
}
+ /** @hide */
+ public static void invalidateDefaultSmsSubIdCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY);
+ }
+
+ /** @hide */
+ public static void invalidateActiveDataSubIdCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY);
+ }
+
+ /** @hide */
+ public static void invalidateSlotIndexCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY);
+ }
+
/**
- * Clears all process-local binder caches.
+ * Allows a test process to disable client-side caching operations.
*
* @hide
*/
+ public static void disableCaching() {
+ sDefaultSubIdCache.disableLocal();
+ sDefaultDataSubIdCache.disableLocal();
+ sActiveDataSubIdCache.disableLocal();
+ sDefaultSmsSubIdCache.disableLocal();
+ sSlotIndexCache.disableLocal();
+ sPhoneIdCache.disableLocal();
+ }
+
+ /**
+ * Clears all process-local binder caches.
+ *
+ * @hide */
public static void clearCaches() {
sDefaultSubIdCache.clear();
sDefaultDataSubIdCache.clear();
+ sActiveDataSubIdCache.clear();
+ sDefaultSmsSubIdCache.clear();
+ sSlotIndexCache.clear();
+ sPhoneIdCache.clear();
}
}
diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java
index 36fa5cc..3d5c6aa 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -62,8 +62,6 @@
* {@link TelephonyManager#NETWORK_TYPE_LTE} network and has E-UTRA-NR Dual Connectivity(EN-DC)
* capability or is currently connected to the secondary
* {@link TelephonyManager#NETWORK_TYPE_NR} cellular network on millimeter wave bands.
- *
- * @see AccessNetworkConstants.NgranBands#FREQUENCY_RANGE_GROUP_2
*/
public static final int OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE = 4;
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index bd531da..43db1d9ce 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -140,8 +140,7 @@
}
/**
- * Receives IMS capability status updates from the ImsService. This information is also
- * available via the {@see #isAvailable(int, int)} method below.
+ * Receives IMS capability status updates from the ImsService.
*
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -194,8 +193,6 @@
* If unavailable, the feature is not able to support the unavailable capability at this
* time.
*
- * This information can also be queried using the {@see #isAvailable(int, int)} API.
- *
* @param capabilities The new availability of the capabilities.
*/
public void onCapabilitiesStatusChanged(
@@ -496,8 +493,7 @@
/**
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
* availability updates for the subscription specified in
- * {@link ImsManager#getImsMmTelManager(int)}. The method {@see #isAvailable(int, int)}
- * can also be used to query this information at any time.
+ * {@link ImsManager#getImsMmTelManager(int)}.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
@@ -639,7 +635,6 @@
* @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
- * @see #setAdvancedCallingSettingEnabled(boolean)
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for advanced calling is enabled, false otherwise.
@@ -858,7 +853,6 @@
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user’s “Video Calling” setting is currently enabled.
- * @see #setVtSettingEnabled(boolean)
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -933,7 +927,6 @@
*
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
- * @see #setVoWiFiSettingEnabled(boolean)
*/
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(anyOf = {
@@ -1011,7 +1004,6 @@
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
- * @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(anyOf = {
@@ -1130,7 +1122,6 @@
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
- * @see #setVoWiFiSettingEnabled(boolean)
*/
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(anyOf = {
@@ -1315,7 +1306,6 @@
*
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
- * @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
*/
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 1dbaff5..e085dec 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -270,7 +270,7 @@
* inactive subscription, it will result in a no-op.
*
* @param c The {@link RegistrationCallback} to be removed.
- * @see SubscriptionManager.OnSubscriptionsChangedListener
+ * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 0b25d6f..b3b7b20 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -218,13 +218,7 @@
* {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and
* {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}.
*
- * The capabilities of this MmTelFeature will be set by the framework and can be queried with
- * {@see #queryCapabilityStatus()}.
- *
- * This MmTelFeature can then return the status of each of these capabilities (enabled or not)
- * by sending a {@see #notifyCapabilitiesStatusChanged} callback to the framework. The current
- * status can also be queried using {@see #queryCapabilityStatus()}.
- * @see #isCapable(int)
+ * The capabilities of this MmTelFeature will be set by the framework.
*/
public static class MmTelCapabilities extends Capabilities {
diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
index 47afed4..efb9203 100644
--- a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
+++ b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
@@ -19,7 +19,10 @@
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import android.net.wifi.WifiNetworkSpecifier;
import android.telephony.SubscriptionManager;
import androidx.test.filters.SmallTest;
@@ -32,6 +35,7 @@
@SmallTest
public class TelephonyNetworkSpecifierTest {
private static final int TEST_SUBID = 5;
+ private static final String TEST_SSID = "Test123";
/**
* Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
@@ -79,4 +83,31 @@
.build();
assertParcelSane(specifier, 1 /* fieldCount */);
}
+
+ /**
+ * Validate the behavior of method canBeSatisfiedBy().
+ */
+ @Test
+ public void testCanBeSatisfiedBy() {
+ final TelephonyNetworkSpecifier tns1 = new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(TEST_SUBID)
+ .build();
+ final TelephonyNetworkSpecifier tns2 = new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(TEST_SUBID)
+ .build();
+ final WifiNetworkSpecifier wns = new WifiNetworkSpecifier.Builder()
+ .setSsid(TEST_SSID)
+ .build();
+ final MatchAllNetworkSpecifier mans = new MatchAllNetworkSpecifier();
+
+ // Test equality
+ assertEquals(tns1, tns2);
+ assertTrue(tns1.canBeSatisfiedBy(tns1));
+ assertTrue(tns1.canBeSatisfiedBy(tns2));
+
+ // Test other edge cases.
+ assertFalse(tns1.canBeSatisfiedBy(null));
+ assertFalse(tns1.canBeSatisfiedBy(wns));
+ assertTrue(tns1.canBeSatisfiedBy(mans));
+ }
}
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index 27ffcdf..04fbbe1 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -45,6 +45,7 @@
SDK_O_MR1 = 27,
SDK_P = 28,
SDK_Q = 29,
+ SDK_R = 30,
};
#endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index b4b6ff1..f9faed8 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -57,6 +57,8 @@
{0x0568, SDK_O},
{0x056d, SDK_O_MR1},
{0x0586, SDK_P},
+ {0x0606, SDK_Q},
+ {0x0617, SDK_R},
};
static bool less_entry_id(const std::pair<uint16_t, ApiVersion>& p, uint16_t entryId) {
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index a00d978..aa9aa12 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -55,6 +55,7 @@
SDK_O_MR1 = 27,
SDK_P = 28,
SDK_Q = 29,
+ SDK_R = 30,
};
ApiVersion FindAttributeSdkLevel(const ResourceId& id);
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index e7a8203..4a6bfd0 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -91,6 +91,7 @@
};
const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
+constexpr int kCurrentDevelopmentVersion = 10000;
/** Retrieves the attribute of the element with the specified attribute resource id. */
static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
@@ -325,7 +326,7 @@
ConfigDescription config;
config.orientation = android::ResTable_config::ORIENTATION_PORT;
config.density = android::ResTable_config::DENSITY_MEDIUM;
- config.sdkVersion = 10000; // Very high.
+ config.sdkVersion = kCurrentDevelopmentVersion; // Very high.
config.screenWidthDp = 320;
config.screenHeightDp = 480;
config.smallestScreenWidthDp = 320;
@@ -622,6 +623,8 @@
}
if (target_sdk) {
extractor()->RaiseTargetSdk(*target_sdk);
+ } else if (target_sdk_name) {
+ extractor()->RaiseTargetSdk(kCurrentDevelopmentVersion);
}
}
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 556cf5e..f4c937c 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -124,13 +124,7 @@
// Print method body.
string indent("");
if (supportQ) {
- // TODO(b/146235828): Use just SDK_INT check once it is incremented from
- // Q.
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
- fprintf(out,
- " || (Build.VERSION.SDK_INT == "
- "Build.VERSION_CODES.Q\n");
- fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
indent = " ";
}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 99beb7b..1e2c81a 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -134,6 +134,7 @@
"framework-wifi-util-lib",
],
sdk_version: "module_current",
+ dist: { dest: "framework-wifi.txt" },
}
droidstubs {
@@ -142,6 +143,16 @@
"framework-module-stubs-defaults-publicapi",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.public.latest",
+ removed_api_file: ":framework-wifi-removed.api.public.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.public.latest",
+ baseline_file: "api/lint-baseline.txt",
+ },
+ },
}
droidstubs {
@@ -150,6 +161,16 @@
"framework-module-stubs-defaults-systemapi",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.system.latest",
+ removed_api_file: ":framework-wifi-removed.api.system.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.system.latest",
+ baseline_file: "api/system-lint-baseline.txt",
+ },
+ },
}
droidstubs {
@@ -158,6 +179,15 @@
"framework-module-api-defaults-module_libs_api",
"framework-wifi-stubs-srcs-defaults",
],
+ check_api: {
+ last_released: {
+ api_file: ":framework-wifi.api.module-lib.latest",
+ removed_api_file: ":framework-wifi-removed.api.module-lib.latest",
+ },
+ api_lint: {
+ new_since: ":framework-wifi.api.module-lib.latest",
+ },
+ },
}
droidstubs {
@@ -172,6 +202,7 @@
name: "framework-wifi-stubs-publicapi",
srcs: [":framework-wifi-stubs-srcs-publicapi"],
defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+ dist: { dest: "framework-wifi.jar" },
}
java_library {
@@ -179,6 +210,7 @@
srcs: [":framework-wifi-stubs-srcs-systemapi"],
libs: ["framework-annotations-lib"],
defaults: ["framework-module-stubs-lib-defaults-systemapi"],
+ dist: { dest: "framework-wifi.jar" },
}
java_library {
@@ -186,6 +218,7 @@
srcs: [":framework-wifi-stubs-srcs-module_libs_api"],
libs: ["framework-annotations-lib"],
defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
+ dist: { dest: "framework-wifi.jar" },
}
// defaults for tests that need to build against framework-wifi's @hide APIs
diff --git a/wifi/api/lint-baseline.txt b/wifi/api/lint-baseline.txt
new file mode 100644
index 0000000..892411f
--- /dev/null
+++ b/wifi/api/lint-baseline.txt
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+GenericException: android.net.wifi.WifiManager.LocalOnlyHotspotReservation#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.MulticastLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.wifi.WifiManager.WifiLock#finalize():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+
+
+VisiblySynchronized: PsiThisExpression:WifiManager.this:
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
+VisiblySynchronized: android.net.wifi.WifiManager.WifiLock#finalize():
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.net.wifi.WifiManager.WifiLock.finalize()
diff --git a/wifi/api/system-lint-baseline.txt b/wifi/api/system-lint-baseline.txt
new file mode 100644
index 0000000..6547ee8
--- /dev/null
+++ b/wifi/api/system-lint-baseline.txt
@@ -0,0 +1,6 @@
+// Baseline format: 1.0
+MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+ android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
+
+MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index e55a89f..26927e5 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -1,6 +1,7 @@
## used by service-wifi ##
# Network Stack AIDL interface.
+rule android.net.DataStallReportParcelable* com.android.wifi.x.@0
rule android.net.DhcpResultsParcelable* com.android.wifi.x.@0
rule android.net.IIpMemoryStore* com.android.wifi.x.@0
rule android.net.IIpMemoryStoreCallbacks* com.android.wifi.x.@0
@@ -14,6 +15,7 @@
rule android.net.Layer2PacketParcelable* com.android.wifi.x.@0
rule android.net.MarkMaskParcel* com.android.wifi.x.@0
rule android.net.NattKeepalivePacketDataParcelable* com.android.wifi.x.@0
+rule android.net.NetworkTestResultParcelable* com.android.wifi.x.@0
rule android.net.PrivateDnsConfigParcel* com.android.wifi.x.@0
rule android.net.ProvisioningConfigurationParcelable* com.android.wifi.x.@0
rule android.net.ResolverParamsParcel* com.android.wifi.x.@0
diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java
index 00cb243..689ace5b 100644
--- a/wifi/java/android/net/wifi/WpsInfo.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -22,7 +22,7 @@
/**
* A class representing Wi-Fi Protected Setup
*
- * {@see WifiP2pConfig}
+ * {@see android.net.wifi.p2p.WifiP2pConfig}
*/
public class WpsInfo implements Parcelable {